Compare commits

...

10 Commits

Author SHA1 Message Date
‘937886381’
1b56696da9 xiugai 2025-10-10 13:12:52 +08:00
zwq
bbd9972761 ry-bug 2025-03-10 16:33:55 +08:00
zwq
8e9b2f6444 更新 2025-02-27 13:54:28 +08:00
zwq
c83a7afadb 更新 2025-02-24 14:10:34 +08:00
zwq
b43876fe67 更新 2025-02-19 14:13:47 +08:00
zwq
f143c5e2d9 . 2025-01-16 08:34:17 +08:00
zwq
0b03e6d44b 更新 2025-01-15 13:35:15 +08:00
zwq
19dbe38458 更新 2025-01-10 15:07:05 +08:00
zwq
43ba33062b 更新 2024-11-29 16:42:13 +08:00
zwq
ca390fd764 更新汝阳bug 2024-11-26 16:51:07 +08:00
119 changed files with 20087 additions and 2876 deletions

View File

@@ -1,7 +1,7 @@
### ###
# @Author: Do not edit # @Author: Do not edit
# @Date: 2023-08-29 09:40:39 # @Date: 2023-08-29 09:40:39
# @LastEditTime: 2024-09-10 14:43:39 # @LastEditTime: 2024-11-25 14:31:39
# @LastEditors: zwq # @LastEditors: zwq
# @Description: # @Description:
### ###
@@ -9,13 +9,11 @@
ENV = 'development' ENV = 'development'
# 页面标题 # 页面标题
VUE_APP_TITLE = 成本管理系统 VUE_APP_TITLE = 智能监控分析系统
# 芋道管理系统/开发环境 # 芋道管理系统/开发环境
# VUE_APP_BASE_API = 'http://192.168.1.49:48080' # VUE_APP_BASE_API = 'http://192.168.8.22:48080'
VUE_APP_BASE_API = 'http://line.kszny.picaiba.com' VUE_APP_BASE_API = 'http://172.16.32.79:48082'
# VUE_APP_BASE_API = 'http://192.168.1.40:48080'
# VUE_APP_BASE_API = 'http://192.168.1.188:48080'
# 路由懒加载 # 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true VUE_CLI_BABEL_TRANSPILE_MODULES = true

View File

@@ -2,14 +2,14 @@
# @Author: zwq # @Author: zwq
# @Date: 2024-03-27 15:49:55 # @Date: 2024-03-27 15:49:55
# @LastEditors: zwq # @LastEditors: zwq
# @LastEditTime: 2024-09-10 15:19:19 # @LastEditTime: 2024-10-30 11:08:47
# @Description: # @Description:
### ###
# 生产环境配置 # 生产环境配置
ENV = 'production' ENV = 'production'
# 页面标题 # 页面标题
VUE_APP_TITLE = 成本管理系统 VUE_APP_TITLE = 智能监控分析系统
# 芋道管理系统/生产环境 # 芋道管理系统/生产环境
# VUE_APP_BASE_API = '/prod-api' # VUE_APP_BASE_API = '/prod-api'

BIN
dist.zip Normal file

Binary file not shown.

View File

@@ -1,3 +1,10 @@
/*
* @Author: zwq
* @Date: 2024-10-29 09:47:40
* @LastEditors: zwq
* @LastEditTime: 2025-02-26 16:27:48
* @Description:
*/
import request from '@/utils/request' import request from '@/utils/request'
// 创建实时数据采集配置 // 创建实时数据采集配置
@@ -52,3 +59,11 @@ export function exportEquipmentPlcExcel(query) {
responseType: 'blob' responseType: 'blob'
}) })
} }
// 获得code
export function getCode() {
return request({
url: '/base/equipment-group/getCode',
method: 'get'
})
}

View File

@@ -1,3 +1,10 @@
/*
* @Author: zwq
* @Date: 2024-10-29 09:47:40
* @LastEditors: zwq
* @LastEditTime: 2025-02-12 09:25:11
* @Description:
*/
import request from '@/utils/request' import request from '@/utils/request'
// 获得工厂产线工段设备树形结构 // 获得工厂产线工段设备树形结构
export function getTree() { export function getTree() {

View File

@@ -51,6 +51,13 @@ export function getCode() {
}) })
} }
// 获得可用的班次列表
export function listClassesEnabled() {
return request({
url: '/base/group-classes/listEnable',
method: 'get'
})
}
// 导出班次基础信息 Excel // 导出班次基础信息 Excel
export function exportGroupClassesExcel(query) { export function exportGroupClassesExcel(query) {
return request({ return request({

View File

@@ -0,0 +1,125 @@
import request from '@/utils/request'
// 创建排班计划配置基础信息
export function createGroupPlan(data) {
return request({
url: '/base/group-scheduling-plan/create',
method: 'post',
data: data
})
}
// 更新排班计划配置基础信息
export function updateGroupPlan(data) {
return request({
url: '/base/group-scheduling-plan/update',
method: 'put',
data: data
})
}
// 删除排班计划配置基础信息
export function deleteGroupPlan(id) {
return request({
url: '/base/group-scheduling-plan/delete?id=' + id,
method: 'delete'
})
}
// 获得排班计划配置基础信息
export function getGroupPlan(id) {
return request({
url: '/base/group-scheduling-plan/get?id=' + id,
method: 'get'
})
}
// 获得排班计划配置基础信息分页
export function getGroupPlanPage(query) {
return request({
url: '/base/group-scheduling-plan/page',
method: 'get',
params: query
})
}
// 获得所有排班计划列表
export function groupPlanList() {
return request({
url: '/base/group-scheduling-plan/listAll',
method: 'get'
})
}
// 获得排班计划相关班组列表
export function groupPlanTeamList(id) {
return request({
url: '/base/group-scheduling-plan-team/teamListByPlanId?planId=' + id,
method: 'get'
})
}
// 获得排班计划相关班次列表
export function groupPlanClassesList(id) {
return request({
url: '/base/group-scheduling-plan-classes/classesListByPlanId?planId=' + id,
method: 'get'
})
}
// 获取code
export function getCode() {
return request({
url: '/base/group-scheduling-plan/getCode',
method: 'get'
})
}
// 导出排班计划配置基础信息 Excel
export function exportGroupPlanExcel(query) {
return request({
url: '/base/group-scheduling-plan/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}
// 获得产线工段树形结构
export function getGroupPlanTree() {
return request({
url: '/base/group-scheduling-plan/getLineSectionTree',
method: 'get'
})
}
// 创建排班计划产线工段
export function createGroupPlanLine(data) {
return request({
url: '/base/group-scheduling-plan-line-section/createPlanLineSection',
method: 'post',
data: data
})
}
// 更新排班计划产线工段
export function updateGroupPlanLine(data) {
return request({
url: '/base/group-scheduling-plan-line-section/updatePlanLineSection',
method: 'put',
data: data
})
}
// 获得排班计划配置基础信息
export function getGroupPlanLine(id) {
return request({
url: '/base/group-scheduling-plan-line-section/getLineSectionByPlanId?planId=' + id,
method: 'get'
})
}
// 获得当前登录用户所在部门id
export function getLoginUserDeptId() {
return request({
url: '/base/group-scheduling-plan-line-section/getLoginUserDeptId',
method: 'get'
})
}

View File

@@ -0,0 +1,60 @@
import request from '@/utils/request'
// 创建排班规则基础信息
export function createGroupRule(data) {
return request({
url: '/base/group-scheduling-rule/create',
method: 'post',
data: data
})
}
// 作废排班规则
export function disableGroupRule(id) {
return request({
url: '/base/group-scheduling-rule/disable?id=' + id,
method: 'post',
})
}
// 更新排班规则基础信息
export function updateGroupRule(data) {
return request({
url: '/base/group-scheduling-rule/update',
method: 'put',
data: data
})
}
// 删除排班规则基础信息
export function deleteGroupRule(id) {
return request({
url: '/base/group-scheduling-rule/delete?id=' + id,
method: 'delete'
})
}
// 获得排班规则基础信息
export function getGroupRule(id) {
return request({
url: '/base/group-scheduling-rule/get?id=' + id,
method: 'get'
})
}
// 获得排班规则基础信息分页
export function getGroupRulePage(query) {
return request({
url: '/base/group-scheduling-rule/page',
method: 'get',
params: query
})
}
// 导出排班规则基础信息 Excel
export function exportGroupRuleExcel(query) {
return request({
url: '/base/group-scheduling-rule/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

View File

@@ -58,3 +58,49 @@ export function listEnabled() {
method: 'get' method: 'get'
}) })
} }
// 获得班组组员信息分页
export function groupTeamPage(query) {
return request({
url: '/base/group-team-det/page',
method: 'get',
params: query
})
}
// 获得班组组员信息
export function groupTeamDet(query) {
return request({
url: '/base/group-team-det/get',
method: 'get',
params: query
})
}
// 创建班组组员信息
export function teamDetCreate(data) {
return request({
url: '/base/group-team-det/create',
method: 'post',
data: data
})
}
// 更新班组组员信息
export function teamDetUpdate(data) {
return request({
url: '/base/group-team-det/update',
method: 'put',
data: data
})
}
// 删除班组组员信息
export function teamDetDelete(query) {
return request({
url: '/base/group-team-det/delete',
method: 'delete',
params: query
})
}

View File

@@ -8,7 +8,14 @@ export function getPreset(query) {
params: query params: query
}) })
} }
// 获取某月预排班
export function getScheduling(query) {
return request({
url: '/base/group-team-scheduling/getScheduling',
method: 'get',
params: query
})
}
// 批量创建-更新排班信息 // 批量创建-更新排班信息
export function createOrUpdateList(data) { export function createOrUpdateList(data) {
return request({ return request({
@@ -25,4 +32,23 @@ export function autoSet(query) {
method: 'get', method: 'get',
params: query params: query
}) })
} }
// 获得排班信息分页
export function schedulingPage(query) {
return request({
url: '/base/group-team-scheduling/page',
method: 'get',
params: query
})
}
// 导出Excel
export function exportSchedulingExcel(query) {
return request({
url: '/base/group-team-scheduling/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

26
src/api/base/worker.js Normal file
View File

@@ -0,0 +1,26 @@
import request from '@/utils/request'
// 获得所有员工列表
export function getWorkerList() {
return request({
url: '/base/core-worker/listAll',
method: 'get'
})
}
// 获得员工
export function getWorker(query) {
return request({
url: '/base/core-worker/get',
method: 'get',
params: query
})
}
// 获得该班组其他可选组员列表(除去现有组员)
export function otherWorkerList(query) {
return request({
url: '/base/group-team-det/otherWorkerList',
method: 'get',
params: query
})
}

View File

@@ -1,8 +1,8 @@
/* /*
* @Author: zhp * @Author: zhp
* @Date: 2023-09-12 14:07:04 * @Date: 2023-09-12 14:07:04
* @LastEditTime: 2023-09-13 09:53:45 * @LastEditTime: 2025-01-08 15:47:17
* @LastEditors: zhp * @LastEditors: zwq
* @Description: * @Description:
*/ */
import request from '@/utils/request' import request from '@/utils/request'
@@ -22,3 +22,26 @@ export function getCT(data) {
data: data data: data
}) })
} }
// 获取产线平衡分析数据new
export function getNewCTNow(data) {
return request({
url: '/analysis/production-analysis/getNewCTNow',
method: 'post',
data: data
})
}
// 获取产线平衡分析数据趋势图new
export function getNewCTCharts(data) {
return request({
url: '/analysis/production-analysis/getNewCTCharts',
method: 'post',
data: data
})
}
// 获取产线平衡分析数据设备listnew
export function getNewCTDet(id) {
return request({
url: '/analysis/production-analysis/getNewCTDet?lineId='+id,
method: 'get',
})
}

View File

@@ -58,3 +58,12 @@ export function exportFactoryExcel(query) {
responseType: 'blob' responseType: 'blob'
}) })
} }
// 获取产线设备状态
export function getLineEqStatus(data) {
return request({
url: '/base/production-line/getLineEqStatus',
method: 'post',
data: data
})
}

View File

@@ -0,0 +1,28 @@
import request from '@/utils/request'
// 切换工艺
export function switchLineBindProcess(data) {
return request({
url: '/base/line-bind-process/switch',
method: 'put',
data: data
})
}
// 获得产线工艺目前生产工艺
export function getLineBindProcessPage(query) {
return request({
url: '/base/line-bind-process/nowList',
method: 'get',
params: query
})
}
// 获得产线工艺log分页
export function getLineBindProcessLogPage(query) {
return request({
url: '/base/line-bind-process/logPage',
method: 'get',
params: query
})
}

View File

@@ -16,6 +16,14 @@ export function switchLineBindProduct(data) {
data: data data: data
}) })
} }
// 切换产线是否可以自动
export function switchAutoProduct(data) {
return request({
url: '/base/line-bind-product/switchAuto',
method: 'put',
data: data
})
}
// 更新产线目前生产产品表 主要为更新 // 更新产线目前生产产品表 主要为更新
export function updateLineBindProduct(data) { export function updateLineBindProduct(data) {
return request({ return request({

View File

@@ -1,9 +1,9 @@
/* /*
* @Author: Do not edit * @Author: Do not edit
* @Date: 2023-09-12 09:44:53 * @Date: 2023-09-12 09:44:53
* @LastEditTime: 2023-09-13 16:11:41 * @LastEditTime: 2025-01-07 09:57:36
* @LastEditors: DY * @LastEditors: zwq
* @Description: * @Description:
*/ */
import request from '@/utils/request' import request from '@/utils/request'
@@ -17,9 +17,52 @@ export function getPdlAutoReport(data) {
} }
// 获得所有工厂产线列表 // 获得所有工厂产线列表
export function getPdList() { export function getPdList(id) {
return request({ return request({
url: '/base/production-line/listAll', url: '/base/production-line/listAll' + (id ? '?id=' + id : ''),
method: 'get' method: 'get'
}) })
} }
// 获得产线自动报表
export function getLineAuto(data) {
return request({
url: '/monitoring/production-monitor/getPdlAutoReportNew',
method: 'post',
data: data
})
}
// 获得产品自动报表
export function getProductAuto(data) {
return request({
url: '/monitoring/production-monitor/getProcessAutoReportNew',
method: 'post',
data: data
})
}
// 班组自动报表分页
export function getTeamReportPage(data) {
return request({
url: '/monitoring/group-off-record/page',
method: 'post',
data: data,
});
}
// 班组自动报表分页详细
export function getTeamReportPageDet(id) {
return request({
url: '/monitoring/group-off-record/get?id=' + id,
method: 'get',
})
}
export function exportGroupProductReportExcel(data) {
return request({
url: '/monitoring/group-off-record/export-det-excel',
method: 'get',
params: data,
responseType: 'blob',
});
}

View File

@@ -1,9 +1,9 @@
/* /*
* @Author: Do not edit * @Author: Do not edit
* @Date: 2023-09-12 09:44:53 * @Date: 2023-09-12 09:44:53
* @LastEditTime: 2023-09-14 10:25:46 * @LastEditTime: 2025-03-03 10:43:34
* @LastEditors: DY * @LastEditors: zwq
* @Description: * @Description:
*/ */
import request from '@/utils/request' import request from '@/utils/request'
@@ -22,4 +22,22 @@ export function getPdList() {
url: '/base/production-line/listAll', url: '/base/production-line/listAll',
method: 'get' method: 'get'
}) })
} }
// 产线统计数据查询-历史
export function getPdlAutoReportNewSearch(data) {
return request({
url: '/monitoring/production-monitor/getPdlAutoReportNewSearch',
method: 'post',
data: data
})
}
// 产线统计数据查询-当前
export function getPdlAutoReportNewSearchNow(data) {
return request({
url: '/monitoring/production-monitor/getPdlAutoReportNewSearchNow',
method: 'post',
data: data,
timeout: 60000,
})
}

18
src/api/material/issue.js Normal file
View File

@@ -0,0 +1,18 @@
import request from '@/utils/request'
// 获得工厂分页
export function getMaterialReceiptIssuePageData(data) {
return request({
url: '/base/material-warehouse-his/page',
method: 'post',
data: data,
});
}
export function createMaterialIssue(data) {
return request({
url: '/base/material-warehouse-his/create',
method: 'post',
data: data,
});
}

45
src/api/order/index.js Normal file
View File

@@ -0,0 +1,45 @@
import request from '@/utils/request'
export function getOrderPage(data) {
return request({
url: '/base/core-work-order/page',
method: 'post',
data: data,
});
}
export function updateOrderData(data) {
return request({
url: '/base/core-work-order/updatee',
method: 'put',
data: data,
});
}
export function createOrderData(data) {
return request({
url: '/base/core-work-order/create',
method: 'post',
data: data,
});
}
export function getOrderData(id) {
return request({
url: '/base/core-work-order/get?id=' + id,
method: 'get',
});
}
export function getOrderCode(data) {
return request({
url: '/base/core-work-order/getCode',
method: 'get',
data: data,
});
}
export function deleteOrder(id) {
return request({
url: '/base/core-work-order/delete?id=' + id,
method: 'delete'
})
}

View File

@@ -1,30 +1,16 @@
<!--
filename: index.vue
author: liubin
date: 2024-04-02 09:49:36
description:
-->
<template> <template>
<!-- 按钮切换 --> <!-- 按钮切换 -->
<div v-if="buttonMode" class="button-nav"> <div v-if="buttonMode" class="button-nav">
<button <button v-for="m in menus" :key="m" @click="handleClick(m)"
v-for="m in menus"
:key="m"
@click="currentMenu = m"
:data-text="m" :data-text="m"
:class="[m === currentMenu ? 'active' : '']" :class="[m === currentMenu ? 'active' : '']"
></button> ></button>
</div> </div>
<!-- 标签切换 --> <!-- 标签切换 -->
<div v-else class="custom-tabs" style="height: 100%; width: 100%"> <div v-else class="custom-tabs" style="height: 100%; width: 100%">
<el-tabs class="tag-nav" v-model="currentMenu" style="height: 100%"> <el-tabs class="tag-nav" v-model="currentMenu" style="height: 100%" @tab-click="handleTabClick">
<el-tab-pane <el-tab-pane v-for="(m, idx) in menus" :key="m" :label="idx == 0 ? `\u2002${m}\u2002` : `\u3000${m}\u3000`"
v-for="(m, idx) in menus" :name="m">
:key="m"
:label="idx == 0 ? `\u2002${m}\u2002` : `\u3000${m}\u3000`"
:name="m"
>
<slot :name="`tab${idx + 1}`"></slot> <slot :name="`tab${idx + 1}`"></slot>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@@ -39,14 +25,17 @@ export default {
type: Array, type: Array,
required: true, required: true,
default: () => [], default: () => [],
validator: (val) => { validator: (val) => val.length > 0,
return val.length > 0;
},
}, },
buttonMode: { buttonMode: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
// 新增支持外部传入选中值v-model 绑定)
value: {
type: String,
default: "",
},
}, },
data() { data() {
return { return {
@@ -54,16 +43,34 @@ export default {
}; };
}, },
created() { created() {
this.currentMenu = this.menus[0]; // 优先使用外部传入的 value否则默认第一个
this.currentMenu = this.value || this.menus[0];
}, },
watch: { watch: {
// 监听外部 value 变化,同步到内部 currentMenu
value(newVal) {
this.currentMenu = newVal;
},
// 监听内部 currentMenu 变化,通知外部
currentMenu(val) { currentMenu(val) {
this.$emit("change", val); this.$emit("input", val); // 触发 v-model 同步
this.$emit("change", val); // 保留原 change 事件
},
},
methods: {
// 按钮点击事件
handleClick(m) {
this.currentMenu = m;
},
// 标签点击事件el-tabs 自带)
handleTabClick(tab) {
this.currentMenu = tab.name;
}, },
}, },
}; };
</script> </script>
<!-- 样式不变 -->
<style scoped lang="scss"> <style scoped lang="scss">
.button-nav { .button-nav {
width: 100%; width: 100%;
@@ -108,22 +115,24 @@ export default {
</style> </style>
<style scoped> <style scoped>
.custom-tabs >>> .el-tabs__header { .custom-tabs>>>.el-tabs__header {
margin-bottom: 8px; margin-bottom: 8px;
display: inline-block; display: inline-block;
/* transform: translateY(-12px); */ /* transform: translateY(-12px); */
} }
.custom-tabs >>> .el-tabs__item {
.custom-tabs>>>.el-tabs__item {
padding-left: 0px !important; padding-left: 0px !important;
padding-right: 0px !important; padding-right: 0px !important;
line-height: 36px !important; line-height: 36px !important;
height: 36px; height: 36px;
} }
.custom-tabs >>> .el-tabs__content { .custom-tabs>>>.el-tabs__content {
height: calc(100% - 42px); height: calc(100% - 42px);
} }
.custom-tabs >>> .el-tab-pane {
.custom-tabs>>>.el-tab-pane {
box-sizing: border-box; box-sizing: border-box;
height: 100%; height: 100%;
padding: 20px; padding: 20px;

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: dialogForm.vue filename: dialogForm.vue
author: liubin author: liubin
date: 2023-08-15 10:32:36 date: 2023-08-15 10:32:36
@@ -92,13 +92,13 @@
{{ col.uploadTips || '只能上传jpg/png文件, 大小不超过2MB' }} {{ col.uploadTips || '只能上传jpg/png文件, 大小不超过2MB' }}
</div> </div>
</el-upload> </el-upload>
<uploadedFile <uploadedFile
class="file" class="file"
v-for="file in form[col.prop] || []" v-for="file in form[col.prop] || []"
:file="file" :file="file"
:key="file.fileUrl" :key="file.fileUrl"
@delete="handleDeleteFile(file)" /> @delete="handleDeleteFile(file)"
@Preview="handlePreview(file)" />
</div> </div>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -138,6 +138,9 @@ const uploadedFile = {
handleDelete() { handleDelete() {
this.$emit('delete', this.file); this.$emit('delete', this.file);
}, },
handlePreview() {
this.$emit('Preview', this.file);
},
}, },
mounted() {}, mounted() {},
render: function (h) { render: function (h) {
@@ -156,7 +159,7 @@ const uploadedFile = {
cursor: 'pointer', cursor: 'pointer',
display: 'inline-block', display: 'inline-block',
}}> }}>
{this.file.fileName} <el-button onClick={this.handlePreview}>{this.file.fileName}</el-button>
<el-button <el-button
type="text" type="text"
icon="el-icon-close" icon="el-icon-close"
@@ -256,6 +259,20 @@ export default {
resetFields(args) { resetFields(args) {
return this.$refs.form.resetFields(args); return this.$refs.form.resetFields(args);
}, },
async handlePreview(file) {
const data = await this.$axios({
url: file.fileUrl,
method: 'get',
responseType: 'blob',
});
const link = document.createElement('a');
link.href = window.URL.createObjectURL(new Blob([data]));
link.download = file.fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(link.href);
},
// getCode // getCode
async getCode(url) { async getCode(url) {
const response = await this.$axios(url); const response = await this.$axios(url);
@@ -355,7 +372,9 @@ export default {
if (!promiseList.length) this.formLoading = false; if (!promiseList.length) this.formLoading = false;
}, },
// 上传成功的特殊处理 // 上传成功的特殊处理
beforeUpload() {}, beforeUpload(file) {
console.log(file)
},
// 上传前的验证规则可通过 bind 属性传入 // 上传前的验证规则可通过 bind 属性传入
handleUploadSuccess(response, file, fileList) { handleUploadSuccess(response, file, fileList) {
this.form.files.push({ this.form.files.push({

View File

@@ -0,0 +1,20 @@
export default {
data() {
return {
tableH: this.tableHeight(260),
};
},
created() {
this.tableH = this?.heightNum ? this.tableHeight(this.heightNum) : this.tableHeight(260);
window.addEventListener('resize', this._setTableHeight);
},
destroyed() {
window.removeEventListener('resize', this._setTableHeight);
},
methods: {
_setTableHeight() {
this.tableH = this?.heightNum ? this.tableHeight(this.heightNum) : this.tableHeight(260);
// this.tableH = this.tableHeight(260);
},
},
};

View File

@@ -76,7 +76,7 @@ export const constantRoutes = [
children: [ children: [
{ {
path: "index", path: "index",
component: (resolve) => require(["@/views/cost/raw/costMaterial/index"], resolve), component: (resolve) => require(["@/views/core/base/factory/index"], resolve),
name: "首页", name: "首页",
meta: { title: "首页", icon: "dashboard", affix: true }, meta: { title: "首页", icon: "dashboard", affix: true },
hidden: true hidden: true

View File

@@ -86,10 +86,11 @@ export const DICT_TYPE = {
// ============== PRODUCT - 产品模块 ============= // ============== PRODUCT - 产品模块 =============
UNIT_DICT: 'unit_dict', UNIT_DICT: 'unit_dict',
PRODUCT_TYPE: 'product_type', PRODUCT_TYPE: 'product_type',
PROCESS_TYPE: 'process_type',
// ============== ENERGY - 能源模块 ============= // ============== ENERGY - 能源模块 =============
ENERGY_UNIT: 'energy_unit', ENERGY_UNIT: 'energy_unit',
// ============== ENERGY - 能源模块 ============= // ============== ENERGY - 能源模块 =============
EQU_ALARM_LEVEL: 'equ_alarm_level', EQU_ALARM_LEVEL: 'equ_alarm_level',
MONITOR_INDEX_TYPE: 'monitor_index_type', MONITOR_INDEX_TYPE: 'monitor_index_type',

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: dialogForm.vue filename: dialogForm.vue
author: liubin author: liubin
date: 2023-09-11 15:55:13 date: 2023-09-11 15:55:13
@@ -71,14 +71,14 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="工段排序" prop="sort"> <el-form-item label="工段设备排序" prop="sort">
<el-input-number <el-input-number
v-model="dataForm.sort" v-model="dataForm.sort"
filterable filterable
min="0" min="0"
max="100" max="100"
@change="$emit('update', dataForm)" @change="$emit('update', dataForm)"
placeholder="请输入工段排序" /> placeholder="请输入工段设备排序" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -112,6 +112,7 @@
{ label: '无类型', value: 0 }, { label: '无类型', value: 0 },
{ label: '进口统计', value: 1 }, { label: '进口统计', value: 1 },
{ label: '出口统计', value: 2 }, { label: '出口统计', value: 2 },
{ label: '进出口计数', value: 3 },
]" ]"
:key="opt.value" :key="opt.value"
:label="opt.label" :label="opt.label"

View File

@@ -4,7 +4,8 @@
<SearchBar <SearchBar
:formConfigs="searchBarFormConfig" :formConfigs="searchBarFormConfig"
ref="search-bar" ref="search-bar"
@headBtnClick="handleSearchBarBtnClick" /> @select-changed="handleSearchBarChanged"
@headBtnClick="buttonClick" />
<!-- 列表 --> <!-- 列表 -->
<base-table <base-table
@@ -52,6 +53,8 @@ import {
getEquipmentBindSectionPage, getEquipmentBindSectionPage,
exportEquipmentBindSectionExcel, exportEquipmentBindSectionExcel,
} from '@/api/base/equipmentBindSection'; } from '@/api/base/equipmentBindSection';
import { getPdList } from '@/api/core/monitoring/auto';
import { getFactoryPage } from '@/api/core/base/factory';
import moment from 'moment'; import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin'; import basicPageMixin from '@/mixins/lb/basicPageMixin';
import DialogForm from './dialogForm.vue'; import DialogForm from './dialogForm.vue';
@@ -61,7 +64,7 @@ export default {
mixins: [basicPageMixin], mixins: [basicPageMixin],
data() { data() {
return { return {
searchBarKeys: ['workshopSectionId', 'equipmentName'], searchBarKeys: ['factoryId','productionLineId','workshopSectionId', 'equipmentName'],
tableBtn: [ tableBtn: [
this.$auth.hasPermi('base:equipment-bind-section:update') this.$auth.hasPermi('base:equipment-bind-section:update')
? { ? {
@@ -84,8 +87,9 @@ export default {
width: 180, width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'), filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
}, },
{ prop: 'productionLine', label: '产线名称' }, { prop: 'factoryName', label: '工厂' },
{ prop: 'workshopSection', label: '工段名称' }, { prop: 'productionLine', label: '产线' },
{ prop: 'workshopSection', label: '工段' },
{ prop: 'equipment', label: '设备名称' }, { prop: 'equipment', label: '设备名称' },
{ prop: 'sort', label: '工段中排序' }, { prop: 'sort', label: '工段中排序' },
{ {
@@ -98,7 +102,7 @@ export default {
prop: 'sectionDataType', prop: 'sectionDataType',
label: '工段数据类型', label: '工段数据类型',
filter: (val) => filter: (val) =>
val != null ? ['无类型', '进口计数', '出口计数'][val] : '-', val != null ? ['无类型', '进口计数', '出口计数', '进出口计数'][val] : '-',
}, },
// { // {
// action: 'show-alert', // action: 'show-alert',
@@ -129,6 +133,20 @@ export default {
// }, // },
], ],
searchBarFormConfig: [ searchBarFormConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'select',
label: '产线',
selectOptions: [],
param: 'productionLineId',
multiple: true,
},
{ {
type: 'select', type: 'select',
label: '工段', label: '工段',
@@ -209,8 +227,8 @@ export default {
label: '产线数据类型', label: '产线数据类型',
options: [ options: [
{ label: '无类型', value: 0 }, { label: '无类型', value: 0 },
{ label: '进口计', value: 1 }, { label: '进口计', value: 1 },
{ label: '出口计', value: 2 }, { label: '出口计', value: 2 },
], ],
prop: 'lineDataType', prop: 'lineDataType',
}, },
@@ -219,8 +237,9 @@ export default {
label: '工段数据类型', label: '工段数据类型',
options: [ options: [
{ label: '无类型', value: 0 }, { label: '无类型', value: 0 },
{ label: '进口计', value: 1 }, { label: '进口计', value: 1 },
{ label: '出口计', value: 2 }, { label: '出口计', value: 2 },
{ label: '进出口计数', value: 3 },
], ],
prop: 'sectionDataType', prop: 'sectionDataType',
}, },
@@ -234,6 +253,9 @@ export default {
pageSize: 10, pageSize: 10,
workshopSectionId: null, workshopSectionId: null,
equipmentId: null, equipmentId: null,
equipmentName: null,
factoryId: null,
productionLineId: [],
}, },
// 表单参数 // 表单参数
form: {}, form: {},
@@ -242,6 +264,7 @@ export default {
created() { created() {
this.getList(); this.getList();
this.initWorksection(); this.initWorksection();
this.getPdLineList();
}, },
methods: { methods: {
/** 准备工段数据 */ /** 准备工段数据 */
@@ -251,7 +274,7 @@ export default {
method: 'get', method: 'get',
}); });
if (code == 0) { if (code == 0) {
this.searchBarFormConfig[0].selectOptions = data.map((item) => { this.searchBarFormConfig[2].selectOptions = data.map((item) => {
return { return {
name: item.name, name: item.name,
id: item.id, id: item.id,
@@ -259,6 +282,51 @@ export default {
}); });
} }
}, },
getPdLineList() {
getPdList().then((res) => {
this.searchBarFormConfig[1].selectOptions = res.data || [];
});
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.searchBarFormConfig[0].selectOptions = res.data.list || [];
});
},
handleSearchBarChanged({ param, value }) {
this.queryParams.productionLineId = [];
this.$refs['search-bar'].formInline.productionLineId = undefined;
getPdList(value).then((res) => {
this.searchBarFormConfig[1].selectOptions = res.data || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.queryParams.pageNo = 1;
this.queryParams.pageSize = 10;
this.queryParams.name = val.name;
this.queryParams.workshopSectionId = val.workshopSectionId || undefined;
this.queryParams.equipmentName = val.equipmentName || undefined;
this.queryParams.factoryId = val.factoryId || undefined;
this.queryParams.productionLineId = val.productionLineId || [];
this.handleQuery();
break;
case 'add':
this.handleAdd();
break;
case 'export':
this.handleExport();
break;
case 'reset':
this.$refs['search-bar'].resetForm();
this.resetQuery();
break;
default:
console.log(val);
}
},
/** 查询列表 */ /** 查询列表 */
getList() { getList() {
this.loading = true; this.loading = true;

View File

@@ -0,0 +1,109 @@
<!--
* @Author: zwq
* @Date: 2021-11-18 14:16:25
* @LastEditors: zwq
* @LastEditTime: 2025-02-26 16:37:29
* @Description:
-->
<template>
<el-row :gutter="20">
<el-form
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="80px">
<el-col :span="12">
<el-form-item label="关联表名" prop="plcTableName">
<el-input
v-model="dataForm.plcTableName"
clearable
placeholder="请输入关联表名" />
</el-form-item>
</el-col>
<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-col :span="12">
<el-form-item label="英文名" prop="enName">
<el-input
v-model="dataForm.enName"
clearable
placeholder="请输入英文名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否采集" prop="collection">
<el-switch
v-model="dataForm.collection"
:active-value="1"
:inactive-value="0"></el-switch>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="描述" prop="description">
<el-input
v-model="dataForm.description"
clearable
placeholder="请输入描述" />
</el-form-item>
</el-col>
</el-form>
</el-row>
</template>
<script>
import basicAdd from '@/mixins/basic-add';
import {
createEquipmentPlc,
updateEquipmentPlc,
getEquipmentPlc,
getCode,
} from '@/api/base/equipmentPlc';
export default {
mixins: [basicAdd],
data() {
return {
urlOptions: {
isGetCode: true,
codeURL: getCode,
createURL: createEquipmentPlc,
updateURL: updateEquipmentPlc,
infoURL: getEquipmentPlc,
},
dataForm: {
id: undefined,
plcTableName: undefined,
code: undefined,
name: undefined,
enName: undefined,
collection: 1,
description: undefined,
},
dataRule: {
plcTableName: [
{ required: true, message: '关联表名不能为空', trigger: 'blur' },
],
code: [{ required: true, message: '编码不能为空', trigger: 'blur' }],
name: [{ required: true, message: '标识不能为空', trigger: 'blur' }],
},
};
},
methods: {},
};
</script>

View File

@@ -1,59 +1,53 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- 搜索工作栏 --> <search-bar
<SearchBar :formConfigs="formConfig"
:formConfigs="searchBarFormConfig" ref="searchBarForm"
ref="search-bar" @headBtnClick="buttonClick" />
@headBtnClick="handleSearchBarBtnClick" />
<!-- 列表 -->
<base-table <base-table
v-loading="dataListLoading"
:table-props="tableProps" :table-props="tableProps"
:page="queryParams.pageNo" :page="listQuery.pageNo"
:limit="queryParams.pageSize" :limit="listQuery.pageSize"
:table-data="list" :table-data="tableData"
ref="pageTable"
@emitFun="handleEmitFun"> @emitFun="handleEmitFun">
<method-btn <method-btn
v-if="tableBtn.length" v-if="tableBtn.length"
slot="handleBtn" slot="handleBtn"
:width="120"
label="操作" label="操作"
:method-list="tableBtn" :method-list="tableBtn"
@clickBtn="handleTableBtnClick" /> @clickBtn="handleClick" />
</base-table> </base-table>
<!-- 分页组件 -->
<pagination <pagination
v-show="total > 0" :limit.sync="listQuery.pageSize"
:total="total" :page.sync="listQuery.pageNo"
:page.sync="queryParams.pageNo" :total="listQuery.total"
:limit.sync="queryParams.pageSize" @pagination="getDataList" />
@pagination="getList" />
<!-- 对话框(添加 / 修改) -->
<base-dialog <base-dialog
:dialogTitle="title" :dialogTitle="addOrEditTitle"
:dialogVisible="open" :dialogVisible="addOrUpdateVisible"
width="700px" @cancel="handleCancel"
@close="cancel" @confirm="handleConfirm"
@cancel="cancel" :before-close="handleCancel"
@confirm="submitForm"> width="50%">
<DialogForm v-if="open" ref="form" v-model="form" :rows="rows" /> <add-or-update
ref="addOrUpdate"
@refreshDataList="successSubmit"></add-or-update>
</base-dialog> </base-dialog>
</div> </div>
</template> </template>
<script> <script>
import AddOrUpdate from './add-or-updata';
import basicPage from '@/mixins/basic-page';
import { parseTime } from '@/filter/code-filter';
import { import {
createEquipmentPlc,
updateEquipmentPlc,
deleteEquipmentPlc, deleteEquipmentPlc,
getEquipmentPlc,
getEquipmentPlcPage, getEquipmentPlcPage,
exportEquipmentPlcExcel, exportEquipmentPlcExcel,
updateEquipmentPlc,
} from '@/api/base/equipmentPlc'; } from '@/api/base/equipmentPlc';
import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin';
const switchBtn = { const switchBtn = {
name: 'SwitchBtn', name: 'SwitchBtn',
@@ -90,49 +84,45 @@ const switchBtn = {
); );
}, },
}; };
const tableProps = [
{ prop: 'code', label: '编码', width: 220 },
{ prop: 'plcTableName', label: '关联表名' },
{ prop: 'name', label: '标识名称' },
{ prop: 'enName', label: '英文名称' },
{
prop: 'collection',
label: '是否采集',
subcomponent: switchBtn,
},
{ prop: 'description', label: '描述' },
];
export default { export default {
name: 'EquipmentPlc', mixins: [basicPage],
mixins: [basicPageMixin],
components: {},
data() { data() {
return { return {
tableKey: Math.random(), urlOptions: {
searchBarKeys: ['name', 'plcTableName'], getDataListURL: getEquipmentPlcPage,
deleteURL: deleteEquipmentPlc,
exportURL: exportEquipmentPlcExcel,
},
tableProps,
tableBtn: [ tableBtn: [
this.$auth.hasPermi('base:equipment-plc:update') this.$auth.hasPermi(`base:equipment-plc:update`)
? { ? {
type: 'edit', type: 'edit',
btnName: '修改', btnName: '编辑',
} }
: undefined, : undefined,
this.$auth.hasPermi('base:equipment-plc:delete') this.$auth.hasPermi(`base:equipment-plc:delete`)
? { ? {
type: 'delete', type: 'delete',
btnName: '删除', btnName: '删除',
} }
: undefined, : undefined,
].filter((v) => v), ].filter((v) => v),
tableProps: [ tableData: [],
// { formConfig: [
// prop: 'createTime',
// label: '添加时间',
// fixed: true,
// width: 180,
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
// },
{ prop: 'code', label: '编码' },
{ prop: 'plcTableName', label: '关联表名' },
{ prop: 'name', label: '标识名称' },
{ prop: 'enName', label: '英文名称' },
{
prop: 'collection',
label: '是否采集',
subcomponent: switchBtn,
},
{ prop: 'description', label: '描述' },
],
searchBarFormConfig: [
{ {
type: 'input', type: 'input',
label: '表名', label: '表名',
@@ -147,231 +137,86 @@ export default {
}, },
{ {
type: 'button', type: 'button',
btnName: '查询', btnName: '搜索',
name: 'search', name: 'search',
color: 'primary', color: 'primary',
}, },
// {
// type: 'separate',
// },
// {
// type: 'button',
// btnName: '重置',
// name: 'reset',
// },
{ {
type: 'separate', type: 'separate',
}, },
{ {
// type: this.$auth.hasPermi('base:equipment-plc:create') type: this.$auth.hasPermi('base:factory:create') ? 'button' : '',
// ? 'button'
// : '',
type: 'button',
btnName: '新增', btnName: '新增',
name: 'add', name: 'add',
plain: true,
color: 'success', color: 'success',
plain: true,
}, },
// { // {
// type: this.$auth.hasPermi('base:equipment-plc:export') ? 'button' : '', // type: this.$auth.hasPermi('base:factory:create') ? 'separate' : '',
// },
// {
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
// btnName: '导出', // btnName: '导出',
// name: 'export', // name: 'export',
// color: 'warning', // color: 'warning',
// }, // },
], ],
rows: [
[
{
input: true,
label: '关联表名',
prop: 'plcTableName',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
// bind: {
// disabled: true, // some condition, like detail mode...
// }
},
{
input: true,
label: '编码',
prop: 'code',
url: '/base/equipment-group/getCode',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
},
],
[
{
input: true,
label: '标识',
prop: 'name',
rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
// bind: {
// disabled: true, // some condition, like detail mode...
// }
},
{
input: true,
label: '英文名',
prop: 'enName',
},
],
[
{
switch: true,
label: '是否采集', // 是否采集 0 代表不采集, 1 代表采集
prop: 'collection',
value: 1,
bind: {
'active-value': 1,
'inactive-value': 0,
},
},
],
[
{
textarea: true,
label: '描述',
prop: 'description',
bind: {
placeholder: '请输入备注',
},
},
],
],
// 是否显示弹出
open: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 10,
plcTableName: null,
name: null,
},
// 表单参数
form: {},
}; };
}, },
created() { components: {
this.getList(); AddOrUpdate,
}, },
created() {},
methods: { methods: {
/** 覆盖 handleEmitFun 的默认实现 */ /** 覆盖 handleEmitFun 的默认实现 */
handleEmitFun({ action, payload }) { handleEmitFun({ action, payload }) {
console.log(payload)
switch (action) { switch (action) {
case 'update-collect': case 'update-collect':
this.reset(); updateEquipmentPlc(payload).then((response) => {
const tempForm = {};
Object.keys(this.form).forEach((key) => {
tempForm[key] = payload[key];
});
updateEquipmentPlc(tempForm).then((response) => {
this.$modal.msgSuccess('修改成功'); this.$modal.msgSuccess('修改成功');
this.open = false; this.getDataList();
this.getList();
}); });
break; break;
} }
}, },
/** 查询列表 */ buttonClick(val) {
getList() { switch (val.btnName) {
this.loading = true; case 'search':
// 执行查询 this.listQuery.pageNo = 1;
getEquipmentPlcPage(this.queryParams).then((response) => { this.listQuery.pageSize = 10;
this.list = response.data.list; this.listQuery.name = val.name;
this.total = response.data.total; this.listQuery.plcTableName = val.plcTableName;
this.loading = false; this.getDataList();
// this.tableKey = Math.random(); // method 1 break;
}); case 'reset':
}, this.$refs.searchBarForm.resetForm();
/** 取消按钮 */ this.listQuery = {
cancel() { pageSize: 10,
this.open = false; pageNo: 1,
this.reset(); total: 1,
}, };
/** 表单重置 */ this.getDataList();
reset() { break;
this.form = { case 'add':
id: undefined, this.addOrEditTitle = '新增';
plcTableName: undefined, this.addOrUpdateVisible = true;
code: undefined, this.addOrUpdateHandle();
name: undefined, break;
enName: undefined, case 'export':
description: undefined, this.handleExport();
collection: undefined, break;
}; default:
this.resetForm('form'); console.log(val);
}, }
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加实时数据采集配置';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getEquipmentPlc(id).then((response) => {
this.form = response.data;
this.open = true;
this.title = '修改实时数据采集配置';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate((valid) => {
if (!valid) {
return;
}
// 修改的提交
if (this.form.id != null) {
updateEquipmentPlc(this.form).then((response) => {
this.$modal.msgSuccess('修改成功');
this.open = false;
this.getList();
});
return;
}
// 添加的提交
createEquipmentPlc(this.form).then((response) => {
this.$modal.msgSuccess('新增成功');
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$modal
.confirm('是否确认删除实时数据采集配置编号为"' + id + '"的数据项?')
.then(function () {
return deleteEquipmentPlc(id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
// 处理查询参数
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal
.confirm('是否确认导出所有实时数据采集配置数据项?')
.then(() => {
this.exportLoading = true;
return exportEquipmentPlcExcel(params);
})
.then((response) => {
this.$download.excel(response, '实时数据采集配置.xls');
this.exportLoading = false;
})
.catch(() => {});
}, },
}, },
}; };

View File

@@ -2,7 +2,7 @@
* @Author: zwq * @Author: zwq
* @Date: 2021-11-18 14:16:25 * @Date: 2021-11-18 14:16:25
* @LastEditors: zwq * @LastEditors: zwq
* @LastEditTime: 2024-04-30 10:01:41 * @LastEditTime: 2025-02-25 16:11:14
* @Description: * @Description:
--> -->
<template> <template>

View File

@@ -0,0 +1,197 @@
<template>
<div
ref="lineChart"
:id="id"
:class="className"
:style="{ height: height, width: width, marginLeft: '10px' }" />
</template>
<script>
import * as echarts from 'echarts';
require('echarts/theme/macarons'); // echarts theme
import resize from '@/utils/chartMixins/resize';
import { parseTime } from '../../mixins/code-filter';
const animationDuration = 1000;
export default {
name: 'lineChart',
mixins: [resize],
props: {
id: {
type: String,
default: 'chart',
},
className: {
type: String,
default: 'chart',
},
title: {
type: String,
default: '',
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: '300px',
},
barData: {
type: Object,
default: () => {},
},
},
data() {
return {
chart: null,
};
},
mounted() {
if (!this.chart) {
this.chart = echarts.init(this.$refs.lineChart);
this.$nextTick(() => {
this.initChart();
});
}
},
beforeDestroy() {
if (!this.chart) {
return;
}
this.chart.dispose();
this.chart = null;
},
watch: {
barData: {
handler() {
if (this.chart) {
this.$nextTick(() => {
this.initChart();
});
} else {
this.$nextTick(() => {
this.chart = echarts.init(this.$refs.lineChart);
this.initChart();
});
}
},
deep: true,
immediate: true,
},
},
methods: {
initChart() {
const _this = this;
this.chart.setOption({
title: {
text: this.title
? '{space|}{tip|}{space|}{value|' + this.title + '}'
: '',
textStyle: {
rich: {
tip: {
width: 6,
height: 6,
borderRadius: 50,
backgroundColor: '#288AFF',
},
space: {
width: 8,
},
value: {
fontSize: 14,
color: 'black',
},
},
},
},
color: ['#288AFF', '#8EF0AB', '#FFDC94'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999',
},
},
},
legend: {
data: ['磨边节拍', '钢化节拍', '下片节拍'],
},
grid: {
containLabel: true,
},
xAxis: {
type: 'category',
data: this.barData.edgeCt.map((item) => {
return parseTime(item.recordTime, '{m}-{d} {h}:{i}');
}),
axisPointer: {
type: 'shadow',
},
},
yAxis: [
{
type: 'value',
name: '节拍 pcs/min',
min: 0,
axisLabel: {
formatter: '{value}',
},
},
],
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
series: [
{
name: '磨边节拍',
type: 'line',
tooltip: {
valueFormatter: function (value) {
return value + 'pcs/min';
},
},
data: this.barData.edgeCt.map((item) => {
return item.ct;
}),
},
{
name: '钢化节拍',
type: 'line',
tooltip: {
valueFormatter: function (value) {
return value + 'pcs/min';
},
},
data: this.barData.temperCt.map((item) => {
return item.ct;
}),
},
{
name: '下片节拍',
type: 'line',
tooltip: {
valueFormatter: function (value) {
return value + 'pcs/min';
},
},
data: this.barData.downCt.map((item) => {
return item.ct;
}),
},
],
});
},
},
};
</script>

View File

@@ -0,0 +1,273 @@
<!--
* @Author: zwq
* @Date: 2023-08-24 14:47:58
* @LastEditors: zwq
* @LastEditTime: 2025-01-09 10:04:17
* @Description:
-->
<template>
<div>
<base-table
:page="1"
:limit="999"
v-loading="dataListLoading"
:table-props="tableProps"
max-height="400"
:table-data="tableData">
<method-btn
v-if="tableData.length"
slot="handleBtn"
:width="80"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<div v-if="eqChartData.length > 0" style="margin-top: 10px">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm1"
@headBtnClick="buttonClick" />
<div
ref="lineChart"
id="chart"
:style="{ height: '400px', width: '100%', marginLeft: '10px' }" />
</div>
</div>
</template>
<script>
import { getNewCTDet, getNewCTCharts } from '@/api/core/analysis/index';
import * as echarts from 'echarts';
require('echarts/theme/macarons'); // echarts theme
import resize from '@/utils/chartMixins/resize';
import { parseTime } from '../../mixins/code-filter';
const tableProps = [
{
prop: 'equipmentName',
label: '设备',
},
{
prop: 'size',
label: '规格',
showOverflowtooltip: true,
},
{
prop: 'process',
label: '产品工艺',
},
{
prop: 'standardCt',
label: '标准节拍pcs/min',
},
{
prop: 'ct',
label: '当前节拍pcs/min',
},
];
export default {
mixins: [resize],
data() {
return {
tableProps,
tableData: [],
tableBtn: [
{
type: 'eqChart',
btnName: '趋势图',
},
].filter((v) => v),
dataListLoading: false,
time: {},
eqChartData: [],
eqName: null,
equipmentId: null,
chart: null,
formConfig: [
{
type: 'datePicker',
label: '时间范围',
dateType: 'datetimerange',
format: 'yyyy-MM-dd HH:mm:ss',
valueFormat: 'timestamp',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
defaultTime: ['00:00:00', '23:59:59'],
param: 'timeVal',
width: 350,
clearable: false,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
],
};
},
components: {},
created() {},
mounted() {},
beforeDestroy() {
if (!this.chart) {
return;
}
this.chart.dispose();
this.chart = null;
},
methods: {
// 获取数据列表
init(lineId, startTime, endTime) {
this.eqChartData = [];
this.time.startTime = startTime;
this.time.endTime = endTime;
this.dataListLoading = true;
getNewCTDet(lineId).then((response) => {
this.tableData = response.data;
this.dataListLoading = false;
});
},
handleClick(val) {
const data = {
...this.time,
equipmentId: val.data.equipmentId,
};
this.eqName = val.data.equipmentName;
this.equipmentId = val.data.equipmentId;
getNewCTCharts(data).then((response) => {
this.eqChartData = response.data;
this.$nextTick(() => {
this.$refs.searchBarForm1.formInline.timeVal = [
this.time.startTime,
this.time.endTime,
];
this.initChart();
});
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.time.startTime = val.timeVal ? val.timeVal[0] : undefined;
this.time.endTime = val.timeVal ? val.timeVal[1] : undefined;
const data = {
...this.time,
equipmentId: this.equipmentId,
};
getNewCTCharts(data).then((response) => {
this.eqChartData = response.data;
this.$nextTick(() => {
this.initChart();
});
});
break;
default:
console.log(val);
}
},
initChart() {
this.chart = echarts.init(this.$refs.lineChart);
const _this = this;
this.chart.setOption({
title: {
text: this.eqName
? '{space|}{tip|}{space|}{value|' + this.eqName + ' 节拍趋势图' + '}'
: '',
textStyle: {
rich: {
tip: {
width: 6,
height: 6,
borderRadius: 50,
backgroundColor: '#288AFF',
},
space: {
width: 8,
},
value: {
fontSize: 14,
color: 'black',
},
},
},
},
color: ['#288AFF', '#8EF0AB', '#FFDC94'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999',
},
},
},
legend: {
data: ['当前节拍', '标准节拍'],
},
grid: {
containLabel: true,
},
xAxis: {
type: 'category',
data: this.eqChartData[0].ct.map((item) => {
return parseTime(item.recordTime, '{m}-{d} {h}:{i}');
}),
axisPointer: {
type: 'shadow',
},
},
yAxis: [
{
type: 'value',
name: '节拍',
min: 0,
interval: 20,
axisLabel: {
formatter: '{value} pcs/min',
},
},
],
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
series: [
{
name: '标准节拍',
type: 'line',
tooltip: {
valueFormatter: function (value) {
return value + 'pcs/min';
},
},
data: this.eqChartData[0].ct.map((item) => {
return item.standardCt;
}),
},
{
name: '当前节拍',
type: 'line',
tooltip: {
valueFormatter: function (value) {
return value + 'pcs/min';
},
},
data: this.eqChartData[0].ct.map((item) => {
return item.ct;
}),
},
],
});
},
},
};
</script>

View File

@@ -0,0 +1,296 @@
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<div v-if="tableData.length">
<base-table
v-loading="dataListLoading"
:span-method="mergeColumnHandler"
:max-height="tableH"
: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"
:total="listQuery.total"
@pagination="getDataList" /> -->
</div>
</template>
<script>
// import basicPage from '../../mixins/basic-page';
import { parseTime } from '../../mixins/code-filter';
import { getCT } from '@/api/core/analysis/index';
import { getProductionLinePage } from '@/api/core/base/productionLine';
import BalanceChart from '../balanceChart';
import { time } from 'echarts';
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
// import { getWorkshopSectionPage } from '@/api/core/base/workshopSection';
// const tableProps = [
// // {
// // prop: 'lineName',
// // label: '产线',
// // align: 'center',
// // },
// // {
// // prop: 'sum',
// // label: '合计',
// // align: 'center',
// // },
// // {
// // prop: 'dynamicValue',
// // label: 'dynamicName',
// // align: 'center',
// // children:[
// // ]
// // }
// ];
export default {
components: {
BalanceChart,
},
mixins: [tableHeightMixin],
data() {
return {
urlOptions: {
getDataListURL: getCT,
},
tableProps: [],
dataListLoading: false,
tableData: [],
listQuery: {
// time: ''
endTime: undefined,
lineId: undefined,
startTime: undefined,
},
timeList: [],
spanArr: [],
xData: [],
yData: [],
optionArrUrl: [getProductionLinePage],
formConfig: [
{
type: 'select',
label: '产线',
selectOptions: [],
param: 'lineIds',
defaultSelect: '',
multiple: false,
filterable: true,
},
{
type: 'datePicker',
label: '时间',
dateType: 'datetimerange',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
width: 350,
param: 'time',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
],
};
},
created() {
this.getArr();
},
methods: {
getArr() {
const params = {
page: 1,
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.urlOptions.getDataListURL(this.listQuery).then((res) => {
console.log(res);
let arr = [
{
prop: 'sectionName',
label: '工段',
align: 'center',
},
{
prop: 'equName',
label: '设备',
align: 'center',
width: 150
},
];
let sectionArr = [];
res.data.data.forEach((ele, index) => {
let tempData = [];
let ggData = [];
let sbluData = [];
let sbsjData = [];
let cxluData = [];
let cxsjData = [];
ele.data.forEach((item, index) => {
item.children.forEach((params) => {
if (params.dynamicName === '生产规格') {
tempData[item.dynamicName + '_gg'] = params.dynamicValue;
ggData[index] = params.dynamicValue;
} else if (params.dynamicName === '设备理论速度') {
tempData[item.dynamicName + '_sblu'] = params.dynamicValue;
sbluData[index] = params.dynamicValue;
} else if (params.dynamicName === '设备实际速度') {
tempData[item.dynamicName + '_sbsj'] = params.dynamicValue;
sbsjData[index] = params.dynamicValue;
} else if (params.dynamicName === '产线理论速度') {
tempData[item.dynamicName + '_cxlu'] = params.dynamicValue;
cxluData[index] = params.dynamicValue;
} else if(params.dynamicName === '产线实际速度') {
tempData[item.dynamicName + '_cxsj'] = params.dynamicValue;
cxsjData[index] = params.dynamicValue;
}
});
});
const equipment = {
name: ele.equName,
ggData: ggData,
sbluData: sbluData,
sbsjData: sbsjData,
cxluData: cxluData,
cxsjData: cxsjData,
};
tempData['equName'] = ele.equName;
tempData['sectionName'] = ele.sectionName;
this.tableData.push(tempData);
const { sectionName } = tempData;
sectionArr.push(sectionName);
this.yData.push(equipment);
});
this.setRowSpan(sectionArr);
res.data.nameData.forEach((item) => {
this.timeList.push(item.name);
});
const timeArray = Array.from(new Set(this.timeList));
console.log(timeArray)
for (const times of timeArray) {
if (times !== '生产规格' && times !== '设备理论速度' && times !== '设备实际速度'
&& times !== '产线理论速度' && times !== '产线实际速度'
) {
const subprop = {
label: times,
align: 'center',
children: [
{ prop: times + '_gg', label: '生产规格', align: 'center' },
{ prop: times + '_sblu', label: '设备理论速度[片/min]', align: 'center' },
{ prop: times + '_sbsj', label: '设备实际速度[片/min]', align: 'center' },
{ prop: times + '_cxlu', label: '产线理论速度[片/min]', align: 'center' },
{ prop: times + '_cxsj', label: '产线实际速度[片/min]', align: 'center' },
],
};
arr.push(subprop);
this.xData.push(times);
}
}
this.tableProps = arr;
console.log(this.$refs)
this.$nextTick(()=>{
this.$refs.lineChart.initChart(this.xData, this.yData);
})
// this.total = response.data.total;
// this.dataListLoading = false;
});
},
buttonClick(val) {
// console.log(val)
switch (val.btnName) {
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();
this.listQuery = {
pageSize: 10,
pageNo: 1,
total: 1,
};
this.getDataList();
break;
default:
console.log(val);
}
},
},
};
</script>

View File

@@ -1,260 +1,302 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2025-01-09 10:27:53
* @LastEditors: zwq
* @Description:
-->
<template> <template>
<div class="app-container"> <div class="app-container">
<search-bar :formConfigs="formConfig" ref="searchBarForm" @headBtnClick="buttonClick" /> <search-bar
<div v-if="tableData.length"> :formConfigs="formConfig"
<base-table v-loading="dataListLoading" :span-method="mergeColumnHandler" :table-props="tableProps" :table-data="tableData" /> ref="searchBarForm"
<SearchBar :formConfigs="[{ label: '产线平衡分析图', type: 'title' }]" /> @select-changed="handleSearchBarChanged"
<balance-chart ref="lineChart" /> @headBtnClick="buttonClick" />
</div> <div v-if="showData.length">
<div v-else class="no-data-bg"></div> <base-table
<!-- <pagination class="right-aside"
:limit.sync="listQuery.pageSize" v-loading="dataListLoading"
:page.sync="listQuery.pageNo" :table-props="tableProps"
:total="listQuery.total" :page="1"
@pagination="getDataList" /> --> :limit="999"
</div> :table-data="showData">
<method-btn
v-if="showData.length"
slot="handleBtn"
:width="80"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<barChart
v-for="item in chartData"
:key="item.name + 'echart'"
style="margin-top: 50px"
height="600px"
:id="item.name + 'echart'"
:title="item.name + ' 节拍趋势图'"
:bar-data="item" />
</div>
<div v-else class="no-data-bg"></div>
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="addOrUpdateVisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
close-on-click-modal
top="0"
width="50%">
<eq-detail ref="eqDetail" />
<slot name="footer">
<el-row slot="footer" type="flex" justify="end">
<el-col :span="24">
<el-button size="small" class="btnTextStyle" @click="handleCancel">
取消
</el-button>
</el-col>
</el-row>
</slot>
</base-dialog>
</div>
</template> </template>
<script> <script>
// import basicPage from '../../mixins/basic-page'; import eqDetail from './eq-detail';
import { parseTime } from '../../mixins/code-filter'; import { parseTime } from '../../mixins/code-filter';
import { getCT } from '@/api/core/analysis/index'; import { getPdList } from '@/api/core/monitoring/auto';
import { getProductionLinePage } from '@/api/core/base/productionLine'; import { getNewCTNow, getNewCTCharts } from '@/api/core/analysis/index';
import BalanceChart from '../balanceChart' import { getFactoryPage } from '@/api/core/base/factory';
import { time } from 'echarts'; // import codeFilter from '../../mixins/code-filter'
// import { getWorkshopSectionPage } from '@/api/core/base/workshopSection'; import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';
import barChart from './BarChart.vue';
// const tableProps = [ const tableProps = [
// // { {
// // prop: 'lineName', prop: 'factoryName',
// // label: '产线', label: '工厂',
// // align: 'center', },
// // }, {
// // { prop: 'lineName',
// // prop: 'sum', label: '产线',
// // label: '合计', },
// // align: 'center', {
// // }, prop: 'size',
// // { label: '规格',
// // prop: 'dynamicValue', showOverflowtooltip: true,
// // label: 'dynamicName', },
// // align: 'center', {
// // children:[ prop: 'process',
label: '产品工艺',
// // ] },
// // } {
// ]; prop: 'edgeCt',
label: '磨边当前节拍pcs/min',
},
{
prop: 'temperCt',
label: '钢化当前节拍pcs/min',
},
{
prop: 'downCt',
label: '下片当前节拍pcs/min',
},
];
export default { export default {
components: { components: {
BalanceChart barChart,
}, eqDetail,
// mixins: [basicPage], },
data() { data() {
return { return {
urlOptions: { urlOptions: {
getDataListURL: getCT, getDataListURL: getNewCTNow,
}, },
tableProps: [], listQuery: {
dataListLoading: false, lineId: [],
tableData: [], },
listQuery: { fileName: '',
// time: '' dataListLoading: false,
endTime: undefined, tableProps,
lineId:undefined, tableBtn: [
startTime:undefined {
}, type: 'eq',
timeList: [], btnName: '详情',
spanArr: [], },
xData: [], ].filter((v) => v),
yData: [], showData: [],
optionArrUrl: [getProductionLinePage], tableData: [],
formConfig: [ chartData: [],
{ formConfig: [
type: 'select', {
label: '产线', type: 'select',
selectOptions: [], label: '工厂',
param: 'lineIds', selectOptions: [],
defaultSelect: '', param: 'factoryId',
multiple: false, onchange: true,
filterable: true, },
}, {
{ type: 'select',
type: 'datePicker', label: '产线',
label: '时间', selectOptions: [],
dateType: 'datetimerange', param: 'lineId',
format: 'yyyy-MM-dd', multiple: true,
valueFormat: 'yyyy-MM-dd HH:mm:ss', },
rangeSeparator: '-', {
startPlaceholder: '开始时间', type: 'datePicker',
endPlaceholder: '结束时间', label: '时间范围',
width: 350, dateType: 'datetimerange',
param: 'time', format: 'yyyy-MM-dd HH:mm:ss',
}, valueFormat: 'timestamp',
{ rangeSeparator: '-',
type: 'button', startPlaceholder: '开始时间',
btnName: '查询', endPlaceholder: '结束时间',
name: 'search', defaultTime: ['00:00:00', '23:59:59'],
color: 'primary', param: 'timeVal',
} width: 350,
], clearable: false,
}; },
}, {
created() { type: 'button',
this.getArr(); btnName: '查询',
}, name: 'search',
methods: { color: 'primary',
getArr() { },
const params = { // {
page: 1, // type: 'separate',
limit: 500 // },
} // {
this.optionArrUrl.forEach((item, index) => { // // type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
item(params).then((response) => { // type: 'button',
this.formConfig[index].selectOptions = response.data.list // btnName: '导出',
}); // name: 'export',
}); // color: 'warning',
}, // },
setRowSpan(arr) { ],
let count = 0 addOrEditTitle: '',
arr.forEach((item, index) => { addOrUpdateVisible: false,
if(index === 0) { };
this.spanArr.push(1) },
} else { created() {
if (item === arr[index - 1]) { // 获取当前时间
this.spanArr[count] += 1 const now = new Date();
this.spanArr.push(0) // 获取前一天的同一时间
} else { const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
count = index // 设置为00:00:00
this.spanArr.push(1) yesterday.setHours(0, 0, 0, 0);
} // 设置为23:59:59
} const end = new Date(yesterday.getTime());
}) end.setHours(23, 59, 59, 59);
}, this.listQuery.startTime = yesterday.getTime();
/** 合并table列的规则 */ this.listQuery.endTime = end.getTime();
mergeColumnHandler({ row, column, rowIndex, columnIndex }) { this.$nextTick(() => {
if (columnIndex == 0) { this.$refs.searchBarForm.formInline.timeVal = [
if (this.spanArr[rowIndex]) { yesterday.getTime(),
return [ end.getTime(),
this.spanArr[rowIndex], // row span ];
1, // col span });
]; this.getDataList();
} else { this.getPdLineList();
return [0, 0]; },
} methods: {
handleExport() {
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;
},
getPdLineList() {
getPdList().then((res) => {
this.formConfig[1].selectOptions = res.data || [];
});
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.lineId = val.lineId ? val.lineId : [];
this.listQuery.startTime = val.timeVal ? val.timeVal[0] : undefined;
this.listQuery.endTime = val.timeVal ? val.timeVal[1] : undefined;
this.getDataList();
break;
case 'export':
this.handleExport();
break;
default:
console.log(val);
} }
}, },
getData() { // 获取数据列表
// this.listQuery.lineId = '1672847052717821953' getDataList() {
// this.listQuery.startTime = '1693497600000'; this.dataListLoading = true;
// this.listQuery.endTime = '1693843200000'; this.urlOptions.getDataListURL(this.listQuery).then((response) => {
this.urlOptions.getDataListURL(this.listQuery).then(res => { this.tableData = response.data;
console.log(res) this.dataListLoading = false;
let arr = [ this.showData = this.tableData;
{ });
prop: 'sectionName', getNewCTCharts(this.listQuery).then((response) => {
label: '工段', this.chartData = response.data;
align: 'center', });
}, },
{ handleSearchBarChanged({ param, value }) {
prop: 'equName', this.listQuery.lineId = [];
label: '设备', this.$refs.searchBarForm.formInline.lineId = undefined;
align: 'center', getPdList(value).then((res) => {
} this.formConfig[1].selectOptions = res.data || [];
] });
let sectionArr= [] },
res.data.data.forEach((ele, index) => { handleClick(val) {
let tempData = [] this.addOrUpdateVisible = true;
let eqData = [] this.addOrEditTitle =
let plData = [] val.data?.factoryName + '-' + val.data?.lineName + ' 详情';
ele.data.forEach((item, index) => { this.$nextTick(() => {
item.children.forEach(params => { this.$refs.eqDetail.init(
if (params.dynamicName === '设备CT') { val.data.lineId,
tempData[item.dynamicName + '_eq'] = params.dynamicValue this.listQuery.startTime,
eqData[index] = params.dynamicValue this.listQuery.endTime
} else { );
tempData[item.dynamicName + '_pl'] = params.dynamicValue });
plData[index] = params.dynamicValue },
} handleCancel() {
}) this.addOrUpdateVisible = false;
}) this.addOrEditTitle = '';
const equipment = { },
name: ele.equName, handleConfirm() {
eqData: eqData, this.handleCancel();
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 => {
this.timeList.push(item.name)
})
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)
}
}
this.tableProps = arr
console.log('表格横坐标', this.xData)
this.$refs.lineChart.initChart(this.xData, this.yData)
// this.total = response.data.total;
// this.dataListLoading = false;
});
},
buttonClick(val) {
// console.log(val)
switch (val.btnName) {
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();
this.listQuery = {
pageSize: 10,
pageNo: 1,
total: 1,
};
this.getDataList();
break;
default:
console.log(val);
}
},
},
}; };
</script> </script>

View File

@@ -1,8 +1,8 @@
<!-- <!--
* @Author: zhp * @Author: zhp
* @Date: 2023-09-13 09:02:25 * @Date: 2023-09-13 09:02:25
* @LastEditTime: 2023-10-08 16:36:37 * @LastEditTime: 2024-11-26 15:52:29
* @LastEditors: DY * @LastEditors: zwq
* @Description: * @Description:
--> -->
<template> <template>
@@ -108,13 +108,28 @@ export default {
}, },
series: [ series: [
{ {
name: '设备CT', name: '生产规格',
data: dataList.eqData, data: dataList.ggData,
type: 'line', type: 'line',
}, },
{ {
name: '产线CT', name: '设备理论速度',
data: dataList.plData, data: dataList.sbluData,
type: 'line',
},
{
name: '设备实际速度',
data: dataList.sbsjData,
type: 'line',
},
{
name: '产线理论速度',
data: dataList.cxluData,
type: 'line',
},
{
name: '产线实际速度',
data: dataList.cxsjData,
type: 'line', type: 'line',
} }
] ]

View File

@@ -1,18 +1,25 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<search-bar :formConfigs="formConfig" ref="searchBarForm" @headBtnClick="buttonClick" /> <search-bar
<div v-if="tableData.length"> :formConfigs="formConfig"
<base-table v-loading="dataListLoading" :table-props="tableProps" :table-data="tableData" /> ref="searchBarForm"
<SearchBar :formConfigs="[{ label: '产品产量对比图', type: 'title' }]" /> @headBtnClick="buttonClick" />
<line-chart ref="lineChart" /> <div v-if="tableData.length">
</div> <base-table
<div v-else class="no-data-bg"></div> v-loading="dataListLoading"
<!-- <pagination :table-props="tableProps"
:max-height="tableH"
: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" :limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo" :page.sync="listQuery.pageNo"
:total="listQuery.total" :total="listQuery.total"
@pagination="getDataList" /> --> @pagination="getDataList" /> -->
</div> </div>
</template> </template>
<script> <script>
@@ -20,7 +27,8 @@
import { parseTime } from '../../mixins/code-filter'; import { parseTime } from '../../mixins/code-filter';
import { getYieldAnalysisPageData } from '@/api/core/analysis/index'; import { getYieldAnalysisPageData } from '@/api/core/analysis/index';
import { getProductionLinePage } from '@/api/core/base/productionLine'; import { getProductionLinePage } from '@/api/core/base/productionLine';
import lineChart from '../LineChart' import lineChart from '../LineChart';
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
// import { getWorkshopSectionPage } from '@/api/core/base/workshopSection'; // import { getWorkshopSectionPage } from '@/api/core/base/workshopSection';
// const tableProps = [ // const tableProps = [
@@ -45,51 +53,52 @@ import lineChart from '../LineChart'
// ]; // ];
export default { export default {
components: { components: {
lineChart, lineChart,
}, },
// mixins: [basicPage], mixins: [tableHeightMixin],
data() { data() {
return { return {
urlOptions: { urlOptions: {
getDataListURL: getYieldAnalysisPageData, getDataListURL: getYieldAnalysisPageData,
}, },
tableProps:[], tableProps: [],
dataListLoading:false, dataListLoading: false,
tableData: [], tableData: [],
listQuery: { listQuery: {
lineIds: [], lineIds: [],
time: '' time: '',
}, },
dateLabelList: [], dateLabelList: [],
optionArrUrl: [getProductionLinePage ], optionArrUrl: [getProductionLinePage],
formConfig: [ formConfig: [
{ {
type: 'select', type: 'select',
label: '产线', label: '产线',
selectOptions: [], selectOptions: [],
param: 'lineIds', param: 'lineIds',
defaultSelect: '', defaultSelect: [],
multiple:true, multiple: true,
filterable: true, filterable: true,
width: 400,
}, },
{ {
type: 'datePicker', type: 'datePicker',
label: '时间', label: '时间',
dateType: 'month', dateType: 'month',
format: 'yyyy-MM-dd', format: 'yyyy-MM',
valueFormat: 'yyyy-MM-dd HH:mm:ss', valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-', rangeSeparator: '-',
startPlaceholder: '开始时间', startPlaceholder: '开始时间',
endPlaceholder: '结束时间', endPlaceholder: '结束时间',
param: 'time', param: 'time',
}, },
{ {
type: 'button', type: 'button',
btnName: '查询', btnName: '查询',
name: 'search', name: 'search',
color: 'primary', color: 'primary',
} },
], ],
}; };
}, },
@@ -104,145 +113,147 @@ export default {
}; };
this.optionArrUrl.forEach((item, index) => { this.optionArrUrl.forEach((item, index) => {
item(params).then((response) => { item(params).then((response) => {
this.formConfig[index].selectOptions = response.data.list this.formConfig[index].selectOptions = response.data.list;
// this.formConfig[0].defaultSelect = response.data.list[0].id // this.formConfig[0].defaultSelect = response.data.list[0].id
this.$set(this.formConfig[0], 'defaultSelect', response.data.list[0].id) // this.$set(this.formConfig[0], 'defaultSelect', response.data.list[0].id)
}); });
}); });
}, },
getData() { getData() {
// this.listQuery.lineIds = ['1672847052717821953'] // this.listQuery.lineIds = ['1672847052717821953']
// this.listQuery.productId = val.productId; // this.listQuery.productId = val.productId;
// this.listQuery.time = '1694486098000'; // this.listQuery.time = '1694486098000';
this.urlOptions.getDataListURL(this.listQuery).then(res => { this.urlOptions.getDataListURL(this.listQuery).then((res) => {
let arr = [ let arr = [
{ {
prop: 'lineName', prop: 'lineName',
label: '产线', label: '产线',
fixed: 'left' fixed: 'left',
}, },
{ {
prop: 'sum', prop: 'sum',
label: '合计', label: '合计[片]',
fixed: 'left' fixed: 'left',
}, },
{ {
prop: res.data ? res.data.nameData[0].name : undefined, prop: res.data ? res.data.nameData[0].name : undefined,
label: res.data ? res.data.nameData[0].name : undefined, label: res.data ? res.data.nameData[0].name : undefined,
align: 'center', align: 'center',
children:[ children: [],
},
];
// 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) {
] // 构造表头
// console.log(res.data.nameData.slice(1)) const props = {
let xData = [] prop: item,
let yAllData = [] label: item,
let lineName = [] };
if (res.data) { arr[2].children.push(props);
let tempDateList = []
res.data.nameData.forEach(date => {
tempDateList.push(date.name)
})
this.dateLabelList = Array.from(new Set(tempDateList))
this.dateLabelList.forEach(item => { // 构造echarts横坐标
if (item.indexOf('年') === -1) { xData.push(item);
// 构造表头 }
const props = { });
'prop': item, // res.data.nameData.slice(1).forEach(item => {
'label': item // const props = {
} // 'prop': item.name,
arr[2].children.push(props) // 'label': item.name,
// 'align': 'center'
// }
// arr[2].children.push(props)
// })
let tableDataArr = [];
res.data.data.forEach((item) => {
let obj = {};
(obj.lineName = item.lineName),
(obj.sum = item.sum),
item.data.forEach((ele, index) => {
// console.log(ele)
ele.children.forEach((e) => {
console.log(e.dynamicName);
obj['' + e.dynamicName + ''] = e.dynamicValue;
console.log(obj['' + e.dynamicName + '']);
});
});
tableDataArr.push(obj);
});
this.tableData = tableDataArr;
this.tableProps = arr;
// 构造echarts横坐标 // let tempList = []
xData.push(item) // res.data.nameData.slice(1).forEach(item => {
} // tempList.push(item.name)
}) // // arr[2].children.push(props)
// res.data.nameData.slice(1).forEach(item => { // })
// const props = { // xData = Array.from(new Set(tempList))
// 'prop': item.name,
// 'label': item.name, res.data.data.forEach((item) => {
// 'align': 'center' let yData = [];
// } lineName.push(item.lineName);
// arr[2].children.push(props) // let obj = {}
// }) // obj.lineName = item.lineName,
let tableDataArr =[] // obj.sum = item.sum,
res.data.data.forEach(item => { item.data.forEach((ele, index) => {
let obj = {} // console.log(ele)
obj.lineName= item.lineName, ele.children.forEach((e) => {
obj.sum= item.sum, // let yData = []
item.data.forEach((ele, index) => { yData.push(e.dynamicValue);
// console.log(ele) });
ele.children.forEach((e) => { });
console.log(e.dynamicName) yAllData.push(yData);
obj['' + e.dynamicName + ''] = e.dynamicValue });
console.log(obj['' + e.dynamicName + '']); console.log(lineName);
}) } else {
}) this.tableProps = arr;
tableDataArr.push(obj) this.tableData = [];
}); xData = [];
this.tableData = tableDataArr yAllData = [];
this.tableProps = arr lineName = [];
}
// let tempList = [] // res.data.data[0].data[0].children.forEach((item, index) => {
// res.data.nameData.slice(1).forEach(item => { // // console.log(item)
// tempList.push(item.name) // yData.push(item.dynamicValue)
// // arr[2].children.push(props) // // let data = 'data' + Number(index+1)
// }) // // obj['' + item.dynamicName + ''] = item.dynamicValue
// xData = Array.from(new Set(tempList)) // })
// console.log(this.yData)
res.data.data.forEach(item => { this.$nextTick(() => {
let yData = [] this.$refs.lineChart.initChart(xData, yAllData, lineName);
lineName.push(item.lineName) });
// let obj = {} // this.total = response.data.total;
// obj.lineName = item.lineName, // this.dataListLoading = false;
// obj.sum = item.sum, });
item.data.forEach((ele, index) => { },
// console.log(ele) buttonClick(val) {
ele.children.forEach((e) => {
// let yData = []
yData.push(e.dynamicValue)
})
})
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)
// // let data = 'data' + Number(index+1)
// // obj['' + item.dynamicName + ''] = item.dynamicValue
// })
// console.log(this.yData)
this.$refs.lineChart.initChart(xData, yAllData, lineName)
// this.total = response.data.total;
// this.dataListLoading = false;
});
},
buttonClick(val) {
switch (val.btnName) { switch (val.btnName) {
case 'search': case 'search':
this.listQuery.lineIds = val.lineIds ? val.lineIds :undefined this.listQuery.lineIds = val.lineIds ? val.lineIds : undefined;
// this.listQuery.productId = val.productId; // this.listQuery.productId = val.productId;
this.listQuery.time = val.time ? new Date(val.time).getTime() : undefined this.listQuery.time = val.time
? new Date(val.time).getTime()
: undefined;
// this.listQuery.pageNo = 1; // this.listQuery.pageNo = 1;
// this.listQuery.pageSize = 10; // this.listQuery.pageSize = 10;
if (val.time) { if (val.time) {
this.getData() this.getData();
} else { } else {
this.$message({ this.$message({
message: '请选择时间', message: '请选择时间',
type: 'warning' type: 'warning',
}); });
} }
break; break;
case 'reset': case 'reset':
this.$refs.searchBarForm.resetForm(); this.$refs.searchBarForm.resetForm();

View File

@@ -59,24 +59,36 @@
<i class="el-icon-delete"></i> <i class="el-icon-delete"></i>
</div> --> </div> -->
<div <div
class="file-list__item"
v-for="(file, index) in files" v-for="(file, index) in files"
:key="file.fileName" :key="file.fileName"
:style="{ style="width: 100%">
background: isPicMode <div
? `url(${file.fileUrl}) no-repeat` class="file-list__item"
: `url(${defaultBg}) no-repeat`, v-if="!isPicMode"
backgroundSize: isPicMode ? '100% 100%' : '64px', :style="{
backgroundPosition: isPicMode ? '0% 0%' : 'center', background: isPicMode
}" ? `url(${file.fileUrl}) no-repeat`
:data-name="file.fileName"> : `url(${defaultBg}) no-repeat`,
<el-button backgroundSize: isPicMode ? '100% 100%' : '64px',
v-if="!disabled" backgroundPosition: isPicMode ? '0% 0%' : 'center',
type="text" }"
class="el-icon-delete" @click="handleDownload(file)"
style="padding: 0" :data-name="file.fileName">
@click="(e) => handleDelete(file)" /> <el-button
</div> v-if="!disabled"
type="text"
class="el-icon-delete"
style="padding: 0"
@click="(e) => handleDelete(file)" />
</div>
<el-image
v-else
class="file-list__item"
style="width: 100%"
:src="file.fileUrl"
:preview-src-list="files.map((item) => item.fileUrl)"></el-image>
</div>
</section> </section>
</div> </div>
</template> </template>
@@ -277,6 +289,32 @@ export default {
// Array // Array
this.$emit('update-filelist', this.appendFilelist); this.$emit('update-filelist', this.appendFilelist);
}, },
async handleDownload(file) {
if (this.isPicMode) {
// this.$emit('preview', file);
const link = document.createElement('a');
link.href = file.fileUrl;
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
// this.$emit('download', file);
const data = await this.$axios({
url: file.fileUrl,
method: 'get',
responseType: 'blob',
});
const link = document.createElement('a');
link.href = window.URL.createObjectURL(new Blob([data]));
link.download = file.fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(link.href);
}
},
}, },
}; };
</script> </script>

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: dialogForm.vue filename: dialogForm.vue
author: liubin author: liubin
date: 2023-08-15 10:32:36 date: 2023-08-15 10:32:36
@@ -44,7 +44,7 @@
<el-date-picker <el-date-picker
v-if="col.datetime" v-if="col.datetime"
v-model="form[col.prop]" v-model="form[col.prop]"
type="datetime" type="date"
:placeholder="`请选择${col.label}`" :placeholder="`请选择${col.label}`"
value-format="timestamp" value-format="timestamp"
v-bind="col.bind"></el-date-picker> v-bind="col.bind"></el-date-picker>

View File

@@ -308,6 +308,7 @@ export default {
}); });
if (code == 0) { if (code == 0) {
this.$modal.msgSuccess('更新成功'); this.$modal.msgSuccess('更新成功');
this.$emit('refreshDataList');
} }
this.btnLoading = false; this.btnLoading = false;

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: dialogForm.vue filename: dialogForm.vue
author: liubin author: liubin
date: 2023-08-15 10:32:36 date: 2023-08-15 10:32:36
@@ -57,6 +57,7 @@
v-model="form.equipmentTypeId" v-model="form.equipmentTypeId"
:disabled="disabled" :disabled="disabled"
filterable filterable
clearable
placeholder="请选择设备类型"> placeholder="请选择设备类型">
<el-option <el-option
v-for="eqType in eqTypeList" v-for="eqType in eqTypeList"
@@ -79,9 +80,9 @@
<el-col :span="8"> <el-col :span="8">
<el-form-item label="生产日期" prop="productionTime" :rules="[]"> <el-form-item label="生产日期" prop="productionTime" :rules="[]">
<el-date-picker <el-date-picker
v-model="form.enterTime" v-model="form.productionTime"
:disabled="disabled" :disabled="disabled"
type="datetime" type="date"
placeholder="请选择生产日期" placeholder="请选择生产日期"
value-format="timestamp"></el-date-picker> value-format="timestamp"></el-date-picker>
</el-form-item> </el-form-item>
@@ -91,14 +92,14 @@
<el-date-picker <el-date-picker
v-model="form.enterTime" v-model="form.enterTime"
:disabled="disabled" :disabled="disabled"
type="datetime" type="date"
placeholder="请选择进场日期" placeholder="请选择进场日期"
value-format="timestamp"></el-date-picker> value-format="timestamp"></el-date-picker>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item <el-form-item
label="设备TT值" label="设备理论生产能效(片/min)"
prop="tvalue" prop="tvalue"
:rules="[ :rules="[
{ required: true, message: '不能为空', trigger: 'blur' }, { required: true, message: '不能为空', trigger: 'blur' },
@@ -112,7 +113,7 @@
<el-input <el-input
v-model="form.tvalue" v-model="form.tvalue"
:disabled="disabled" :disabled="disabled"
placeholder="请输入设备TT值"></el-input> placeholder="请输入"></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -316,7 +317,7 @@ export default {
this.form this.form
); );
// 保存原始文件名 // 保存原始文件名
if ('fileNames' in this.form) this.form.fileNames.push(file.name); if ('fileNames' in this.form) this.form.fileNames.push(file.name+Date.now());
// 保存完整地址 // 保存完整地址
if ('fileUrls' in this.form) this.form.fileUrls.push(response.data); if ('fileUrls' in this.form) this.form.fileUrls.push(response.data);
this.$modal.msgSuccess('上传成功'); this.$modal.msgSuccess('上传成功');

View File

@@ -38,7 +38,7 @@
@cancel="cancel" @cancel="cancel"
width="60%" width="60%"
@confirm="submitForm"> @confirm="submitForm">
<DialogForm <DialogForm1
v-if="open" v-if="open"
key="index-dialog-form" key="index-dialog-form"
ref="form" ref="form"
@@ -78,7 +78,7 @@
queryParams: { queryParams: {
equipmentId: form.id, equipmentId: form.id,
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 20,
}, },
tableBtn: [ tableBtn: [
this.$auth.hasPermi('base:equipment-attr:update') this.$auth.hasPermi('base:equipment-attr:update')
@@ -107,6 +107,7 @@
import moment from 'moment'; import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin'; import basicPageMixin from '@/mixins/lb/basicPageMixin';
import EquipmentDrawer from './components/EquipmentDrawer'; import EquipmentDrawer from './components/EquipmentDrawer';
import DialogForm1 from './components/DialogForm';
import { import {
createEquipment, createEquipment,
@@ -124,6 +125,7 @@ export default {
components: { components: {
Editor, Editor,
EquipmentDrawer, EquipmentDrawer,
DialogForm1,
}, },
mixins: [basicPageMixin], mixins: [basicPageMixin],
data() { data() {
@@ -157,7 +159,12 @@ export default {
width: 180, width: 180,
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'), filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
}, },
{ prop: 'name', label: '设备名称' }, {
width: 200,
showOverflowtooltip: true,
prop: 'name',
label: '设备名称',
},
{ width: 256, prop: 'code', label: '设备编码' }, { width: 256, prop: 'code', label: '设备编码' },
{ prop: 'equipmentType', label: '设备类型' }, { prop: 'equipmentType', label: '设备类型' },
{ prop: 'enName', label: '英文名称' }, { prop: 'enName', label: '英文名称' },
@@ -270,6 +277,7 @@ export default {
url: '/base/equipment-type/page?pageNo=1&pageSize=100', url: '/base/equipment-type/page?pageNo=1&pageSize=100',
bind: { bind: {
filterable: true, filterable: true,
clearable: true,
}, },
}, },
// { // {
@@ -294,7 +302,7 @@ export default {
{ {
input: true, input: true,
prop: 'tvalue', prop: 'tvalue',
label: '设备TT值', label: '设备理论生产能效(片/min)',
rules: [ rules: [
{ required: true, message: '不能为空', trigger: 'blur' }, { required: true, message: '不能为空', trigger: 'blur' },
{ {
@@ -435,7 +443,7 @@ export default {
// 查询参数 // 查询参数
queryParams: { queryParams: {
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 20,
code: '', code: '',
name: '', name: '',
}, },
@@ -561,6 +569,7 @@ export default {
return; return;
} }
// 添加的提交 // 添加的提交
this.form.files = [];
createEquipment(this.form).then((response) => { createEquipment(this.form).then((response) => {
this.$modal.msgSuccess('新增成功'); this.$modal.msgSuccess('新增成功');
this.open = false; this.open = false;

View File

@@ -153,6 +153,9 @@ export default {
label: '父类', label: '父类',
prop: 'parentId', prop: 'parentId',
url: '/base/equipment-type/page?pageNo=1&pageSize=100', url: '/base/equipment-type/page?pageNo=1&pageSize=100',
bind: {
clearable: true, // some condition, like detail mode...
}
}, },
{}, {},
], ],
@@ -237,25 +240,6 @@ export default {
const id = row.id; const id = row.id;
getEquipmentType(id).then((response) => { getEquipmentType(id).then((response) => {
this.form = response.data; 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.open = true;
this.title = '修改设备类型'; this.title = '修改设备类型';
}); });

View File

@@ -0,0 +1,99 @@
<!--
* @Author: zwq
* @Date: 2023-08-02 15:12:42
* @LastEditors: zwq
* @LastEditTime: 2024-11-29 13:25:51
* @Description:
-->
<template>
<div class="app-container">
<search-bar
:formConfigs="[{ label: '产线在制工艺', type: 'title' }]"
ref="searchBarForm" />
<base-table
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="tableData"
@emitFun="inputChange" />
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
</div>
</template>
<script>
import basicPage from '../../mixins/basic-page';
import { parseTime } from '../../mixins/code-filter';
import { getLineBindProcessPage } from '@/api/core/base/lineBindProcess';
import selectProduct from './selectProduct';
const tableProps = [
{
prop: 'lineName',
label: '产线'
},
{
prop: 'processDictName',
label: '在制工艺',
list: [],
subcomponent: selectProduct,
},
{
prop: 'recordTime',
label: '开始时间',
filter: parseTime,
},
];
export default {
mixins: [basicPage, selectProduct],
data() {
return {
urlOptions: {
getDataListURL: getLineBindProcessPage,
},
tableProps,
tableData: [],
// formConfig: [
// {
// type: 'button',
// btnName: '同步',
// name: 'search',
// color: 'primary',
// },
// ],
};
},
components: {},
created() {
},
methods: {
// 获取数据列表
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then(response => {
this.tableData = response.data;
this.dataListLoading = false;
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.getDataList();
break;
default:
console.log(val);
}
},
inputChange() {
this.getDataList();
},
},
};
</script>

View File

@@ -0,0 +1,83 @@
<!--
* @Author: zwq
* @Date: 2023-08-03 14:09:18
* @LastEditors: zwq
* @LastEditTime: 2025-02-24 15:21:07
* @Description:
-->
<template>
<div class="tableInner">
<el-popover
placement="top"
title="切换在制工艺"
width="160"
v-model="visible">
<el-select v-model="list.processDict" style="margin: 5px" filterable>
<el-option
v-for="opt in getDictDatas(DICT_TYPE.PROCESS_TYPE)"
:key="opt.value"
:label="opt.label"
:value="opt.value"></el-option>
</el-select>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="visible = false">
取消
</el-button>
<el-button type="primary" size="mini" @click="changeInput">
确定
</el-button>
</div>
<el-button type="text" slot="reference">
<svg-icon icon-class="changelogo" />
</el-button>
</el-popover>
<el-input
readonly
v-model="list.processDictName"
style="width: 50%; margin-left: 5px"></el-input>
</div>
</template>
<script>
import { switchLineBindProcess } from '@/api/core/base/lineBindProcess';
export default {
props: {
injectData: {
type: Object,
default: () => ({}),
},
},
data() {
return {
list: this.injectData,
visible: false,
};
},
mounted() {
},
methods: {
changeInput() {
const processDictName = this.getDictDatas(this.DICT_TYPE.PROCESS_TYPE).find(item=>
item.value == this.list.processDict
)
const data = {
id: this.list.id,
processDict: this.list.processDict,
processDictName: processDictName.label,
};
switchLineBindProcess(data).then((response) => {
this.$modal.msgSuccess('修改成功');
this.visible = false;
this.$emit('emitData');
});
},
},
};
</script>
<style scoped>
.tableInner .el-input__inner {
border: none;
padding: 0;
height: 33px;
}
</style>

View File

@@ -0,0 +1,164 @@
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@select-changed="handleSearchBarChanged"
@headBtnClick="buttonClick" />
<base-table
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="tableData" />
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
</div>
</template>
<script>
import basicPage from '../../mixins/basic-page';
import { parseTime } from '../../mixins/code-filter';
import { getLineBindProcessLogPage } from '@/api/core/base/lineBindProcess';
import { getProductionLinePage } from '@/api/core/base/productionLine';
import { getPdList } from '@/api/core/monitoring/auto';
import { getFactoryPage } from '@/api/core/base/factory';
const tableProps = [
{
prop: 'factoryName',
label: '工厂'
},
{
prop: 'lineName',
label: '产线',
},
{
prop: 'processDictName',
label: '在制工艺',
},
{
prop: 'recordTime',
label: '开始时间',
filter: parseTime,
},
];
export default {
mixins: [basicPage],
data() {
return {
urlOptions: {
getDataListURL: getLineBindProcessLogPage,
},
tableProps,
tableData: [],
optionArrUrl: [getFactoryPage,getProductionLinePage],
listQuery: {
productionLineId: [],
},
formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'select',
label: '产线',
selectOptions: [],
param: 'productionLineId',
multiple: true,
},
{
type: 'select',
label: '在制工艺',
selectOptions: this.getDictDatas(this.DICT_TYPE.PROCESS_TYPE),
labelField: 'label',
valueField: 'value',
param: 'processDict',
defaultSelect: '',
filterable: true,
},
{
type: 'datePicker',
label: '时间',
dateType: 'daterange',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'startTime',
},
{
type: 'button',
btnName: '搜索',
name: 'search',
color: 'primary',
},
{
type: 'button',
btnName: '重置',
name: 'reset',
},
],
};
},
components: {},
created() {
this.getArr();
},
methods: {
handleSearchBarChanged({ param, value }) {
this.listQuery.productionLineId = [];
this.$refs.searchBarForm.formInline.productionLineId = undefined;
getPdList(value).then((res) => {
this.formConfig[1].selectOptions = res.data || [];
});
},
getArr() {
const params = {
page: 1,
limit: 500,
};
this.optionArrUrl.forEach((item, index) => {
item(params).then((response) => {
this.formConfig[index].selectOptions = response.data.list;
});
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.productionLineId = val.productionLineId || [];
this.listQuery.processDict = val.processDict;
this.listQuery.recordTime = val.startTime
? [val.startTime[0], val.startTime[1].substr(0, 10) + ' 23:59:59']
: null;
this.getDataList();
break;
case 'reset':
this.$refs.searchBarForm.resetForm();
this.listQuery = {
pageSize: 10,
pageNo: 1,
total: 1,
};
this.getDataList();
break;
default:
console.log(val);
}
},
},
};
</script>

View File

@@ -0,0 +1,53 @@
<!--
* @Author: zhp
* @Date: 2023-01-31 14:12:10
* @LastEditTime: 2024-11-29 10:49:37
* @LastEditors: zwq
* @Description:
-->
<template>
<span>
<el-switch
@change="changeStatus"
v-model="injectData.allowAuto"
:active-value="true"
:inactive-value="false"></el-switch>
</span>
</template>
<script>
import { switchAutoProduct } from '@/api/core/base/lineBindProduct';
export default {
props: {
injectData: {
type: Object,
default: () => ({}),
},
},
data() {
return {
urlOptions: {
submitURL: switchAutoProduct,
},
};
},
methods: {
// 子级
changeStatus() {
// 路由参数
let obj = {
allowAuto: this.injectData.allowAuto,
id: this.injectData.id,
};
this.urlOptions.submitURL(obj).then((res) => {
console.log(res)
if (res.code !== 0) {
return this.$message.error(res.msg);
}
this.$modal.msgSuccess('切换状态成功');
this.$emit('emitData');
});
},
},
};
</script>

View File

@@ -1,8 +1,8 @@
<!-- <!--
* @Author: zwq * @Author: zwq
* @Date: 2023-08-02 15:12:42 * @Date: 2023-08-02 15:12:42
* @LastEditors: DY * @LastEditors: zwq
* @LastEditTime: 2023-10-13 16:35:03 * @LastEditTime: 2024-11-29 10:47:46
* @Description: * @Description:
--> -->
<template> <template>
@@ -30,6 +30,7 @@ import basicPage from '../../mixins/basic-page';
import { parseTime } from '../../mixins/code-filter'; import { parseTime } from '../../mixins/code-filter';
import { getLineBindProductPage } from '@/api/core/base/lineBindProduct'; import { getLineBindProductPage } from '@/api/core/base/lineBindProduct';
import selectProduct from './selectProduct'; import selectProduct from './selectProduct';
import changeStatus from './changeStatus';
import { getProductPage } from '@/api/core/base/product'; import { getProductPage } from '@/api/core/base/product';
const tableProps = [ const tableProps = [
@@ -43,6 +44,11 @@ const tableProps = [
list: [], list: [],
subcomponent: selectProduct, subcomponent: selectProduct,
}, },
{
prop: 'allowAuto',
label: '允许自动',
subcomponent: changeStatus,
},
{ {
prop: 'recordTime', prop: 'recordTime',
label: '开始时间', label: '开始时间',

View File

@@ -3,6 +3,7 @@
<search-bar <search-bar
:formConfigs="formConfig" :formConfigs="formConfig"
ref="searchBarForm" ref="searchBarForm"
@select-changed="handleSearchBarChanged"
@headBtnClick="buttonClick" /> @headBtnClick="buttonClick" />
<base-table <base-table
v-loading="dataListLoading" v-loading="dataListLoading"
@@ -24,15 +25,21 @@ import { parseTime } from '../../mixins/code-filter';
import { getLineBindProductLogPage } from '@/api/core/base/lineBindProductLog'; import { getLineBindProductLogPage } from '@/api/core/base/lineBindProductLog';
import { getProductionLinePage } from '@/api/core/base/productionLine'; import { getProductionLinePage } from '@/api/core/base/productionLine';
import { getProductPage } from '@/api/core/base/product'; import { getProductPage } from '@/api/core/base/product';
import { getFactoryPage } from '@/api/core/base/factory';
import { getPdList } from '@/api/core/monitoring/auto';
const tableProps = [ const tableProps = [
{
prop: 'factoryName',
label: '工厂'
},
{ {
prop: 'productionLineName', prop: 'productionLineName',
label: '产线' label: '产线',
}, },
{ {
prop: 'productName', prop: 'productName',
label: '在制产品' label: '在制产品',
}, },
{ {
prop: 'startTime', prop: 'startTime',
@@ -55,15 +62,24 @@ export default {
}, },
tableProps, tableProps,
tableData: [], tableData: [],
optionArrUrl: [getProductionLinePage, getProductPage], listQuery: {
productionLineId: [],
},
optionArrUrl: [getFactoryPage,getProductionLinePage, getProductPage],
formConfig: [ formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{ {
type: 'select', type: 'select',
label: '产线', label: '产线',
selectOptions: [], selectOptions: [],
param: 'productionLineId', param: 'productionLineId',
defaultSelect: '', multiple: true,
filterable: true,
}, },
{ {
type: 'select', type: 'select',
@@ -83,7 +99,7 @@ export default {
startPlaceholder: '开始时间', startPlaceholder: '开始时间',
endPlaceholder: '结束时间', endPlaceholder: '结束时间',
param: 'startTime', param: 'startTime',
valueFormat: 'timestamp' valueFormat: 'timestamp',
}, },
{ {
type: 'button', type: 'button',
@@ -99,12 +115,18 @@ export default {
], ],
}; };
}, },
components: { components: {},
},
created() { created() {
this.getArr(); this.getArr();
}, },
methods: { methods: {
handleSearchBarChanged({ param, value }) {
this.listQuery.productionLineId = [];
this.$refs.searchBarForm.formInline.productionLineId = undefined;
getPdList(value).then((res) => {
this.formConfig[1].selectOptions = res.data || [];
});
},
getArr() { getArr() {
const params = { const params = {
page: 1, page: 1,
@@ -121,9 +143,10 @@ export default {
case 'search': case 'search':
this.listQuery.pageNo = 1; this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10; this.listQuery.pageSize = 10;
this.listQuery.productionLineId = val.productionLineId; this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.productionLineId = val.productionLineId || [];
this.listQuery.productId = val.productId; this.listQuery.productId = val.productId;
this.listQuery.startTime = val.startTime; this.listQuery.startTime = val.startTime ? val.startTime : null;
this.getDataList(); this.getDataList();
break; break;
case 'reset': case 'reset':

View File

@@ -72,19 +72,37 @@
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="规格" prop="specifications"> <el-form-item label="原片规格" prop="originalSpecifications">
<el-input <el-input
:disabled="isdetail" :disabled="isdetail"
v-model="dataForm.specifications" v-model="dataForm.originalSpecifications"
placeholder="请输入规格" /> placeholder="请输入原片规格" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="单位平方数" prop="area"> <el-form-item label="原片单位平方数" prop="originalArea">
<el-input
:disabled="isdetail"
v-model="dataForm.originalArea"
placeholder="请输入原片单位平方数" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="深加工规格" prop="specifications">
<el-input
:disabled="isdetail"
v-model="dataForm.specifications"
placeholder="请输入深加工规格" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="深加工单位平方数" prop="area">
<el-input <el-input
:disabled="isdetail" :disabled="isdetail"
v-model="dataForm.area" v-model="dataForm.area"
placeholder="请输入单位平方数" /> placeholder="请输入深加工单位平方数" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -154,7 +172,9 @@
<el-button v-if="isdetail" type="primary" @click="goEdit()"> <el-button v-if="isdetail" type="primary" @click="goEdit()">
编辑 编辑
</el-button> </el-button>
<el-button v-else type="primary" @click="dataFormSubmit()">确定</el-button> <el-button v-else type="primary" @click="dataFormSubmit()">
确定
</el-button>
</div> </div>
<product-attr-add <product-attr-add
@@ -220,11 +240,13 @@ export default {
id: null, id: null,
name: '', // 产品名称 name: '', // 产品名称
code: '', // 产品编码 code: '', // 产品编码
area: 0, // 单位平方数(float only) area: 0, // 深加工单位平方数(float only)
typeDictValue: null, // 产品类型id typeDictValue: null, // 产品类型id
processTime: null, // 单位产品用时 (s) processTime: null, // 单位产品用时 (s)
specifications: '', // 规格 specifications: '', // 深加工规格
unitDictValue: '', // 单位id unitDictValue: '', // 单位id
originalSpecifications: '', // 原片规格
originalArea: 0, // 原片单位平方数
}, },
listQuery: { listQuery: {
pageSize: 10, pageSize: 10,
@@ -371,8 +393,19 @@ export default {
// 添加的提交 // 添加的提交
createProduct(this.dataForm).then((response) => { createProduct(this.dataForm).then((response) => {
this.$modal.msgSuccess('新增成功'); this.$modal.msgSuccess('新增成功');
this.visible = false; this.$confirm(`是否新增产品属性?`, '系统提示', {
this.$emit('refreshDataList'); confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.dataForm.id = response.data
this.addNew();
})
.catch(() => {
this.visible = false;
this.$emit('refreshDataList');
});
}); });
} }
}); });
@@ -382,10 +415,14 @@ export default {
}, },
// 新增 / 修改 // 新增 / 修改
addNew(id) { addNew(id) {
this.addOrUpdateVisible = true; if (this.dataForm.id) {
this.$nextTick(() => { this.addOrUpdateVisible = true;
this.$refs.addOrUpdate.init(id); this.$nextTick(() => {
}); this.$refs.addOrUpdate.init(id);
});
} else {
this.$message('请先创建产品!');
}
}, },
goback() { goback() {
this.$emit('refreshDataList'); this.$emit('refreshDataList');

View File

@@ -1,8 +1,8 @@
<!-- <!--
* @Author: zwq * @Author: zwq
* @Date: 2023-08-01 14:55:51 * @Date: 2023-08-01 14:55:51
* @LastEditors: DY * @LastEditors: zwq
* @LastEditTime: 2023-10-13 10:27:00 * @LastEditTime: 2025-02-24 16:06:59
* @Description: * @Description:
--> -->
<template> <template>
@@ -49,27 +49,31 @@ import {
const tableProps = [ const tableProps = [
{ {
prop: 'code', prop: 'createTime',
label: '产品编码' label: '创建时间',
filter: parseTime
}, },
{ {
prop: 'name', prop: 'name',
label: '产品名称' label: '产品名称'
}, },
{
prop: 'code',
label: '产品编码'
},
{
prop: 'originalSpecifications',
label: '原片规格'
},
{ {
prop: 'specifications', prop: 'specifications',
label: '规格' label: '深加工规格'
}, },
{ {
prop: 'unitDictValue', prop: 'unitDictValue',
label: '单位', label: '单位',
subcomponent: unitDict, subcomponent: unitDict,
}, },
{
prop: 'createTime',
label: '创建时间',
filter: parseTime
},
]; ];
export default { export default {

View File

@@ -2,7 +2,7 @@
* @Author: zwq * @Author: zwq
* @Date: 2023-08-01 13:52:10 * @Date: 2023-08-01 13:52:10
* @LastEditors: zwq * @LastEditors: zwq
* @LastEditTime: 2024-04-10 16:31:51 * @LastEditTime: 2025-02-24 15:32:45
* @Description: * @Description:
--> -->
<template> <template>
@@ -12,6 +12,7 @@
:rules="dataRule" :rules="dataRule"
ref="dataForm" ref="dataForm"
@keyup.enter.native="dataFormSubmit()" @keyup.enter.native="dataFormSubmit()"
label-position="top"
label-width="90px"> label-width="90px">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
@@ -48,11 +49,11 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="产线TT值(h)" prop="tvalue"> <el-form-item label="产线理论生产能效(片/min)" prop="tvalue">
<el-input <el-input
v-model="dataForm.tvalue" v-model="dataForm.tvalue"
clearable clearable
placeholder="请输入每小时下片数量" /> placeholder="请输入数量" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -80,6 +81,17 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="描述" prop="description">
<el-input
v-model="dataForm.description"
type="textarea"
placeholder="请输入内容" />
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input
@@ -89,17 +101,6 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </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-col>
</el-row>
</el-form> </el-form>
</template> </template>
@@ -139,11 +140,11 @@ export default {
}, },
pdTypeArr: [ pdTypeArr: [
{ {
id: 0, id: '0',
name: '深加工' name: '深加工'
}, },
{ {
id: 1, id: '1',
name: '原片' name: '原片'
} }
], ],
@@ -159,6 +160,7 @@ export default {
], ],
tvalue: [ tvalue: [
{ {
required: true,
type: 'number', type: 'number',
message: '请输入正确的数字', message: '请输入正确的数字',
trigger: 'change', trigger: 'change',

View File

@@ -48,6 +48,7 @@ import {
exportProductionLineExcel, exportProductionLineExcel,
getStatus, getStatus,
} from '@/api/core/base/productionLine'; } from '@/api/core/base/productionLine';
import { getFactoryPage } from '@/api/core/base/factory';
const tableProps = [ const tableProps = [
{ {
@@ -121,6 +122,13 @@ export default {
].filter((v) => v), ].filter((v) => v),
tableData: [], tableData: [],
formConfig: [ formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{ {
type: 'input', type: 'input',
label: '产线名称', label: '产线名称',
@@ -168,7 +176,15 @@ export default {
components: { components: {
AddOrUpdate, AddOrUpdate,
}, },
created() {}, created() {
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
methods: { methods: {
// 获取数据列表 // 获取数据列表
getDataList() { getDataList() {
@@ -197,6 +213,7 @@ export default {
case 'search': case 'search':
this.listQuery.pageNo = 1; this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10; this.listQuery.pageSize = 10;
this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.name = val.name; this.listQuery.name = val.name;
this.getDataList(); this.getDataList();
break; break;

View File

@@ -3,6 +3,7 @@
<search-bar <search-bar
:formConfigs="formConfig" :formConfigs="formConfig"
ref="searchBarForm" ref="searchBarForm"
@select-changed="handleSearchBarChanged"
@headBtnClick="buttonClick" /> @headBtnClick="buttonClick" />
<base-table <base-table
v-loading="dataListLoading" v-loading="dataListLoading"
@@ -46,6 +47,8 @@ import {
getWorkshopSectionPage, getWorkshopSectionPage,
exportWorkshopSectionExcel exportWorkshopSectionExcel
} from "@/api/core/base/workshopSection"; } from "@/api/core/base/workshopSection";
import { getPdList } from '@/api/core/monitoring/auto';
import { getFactoryPage } from '@/api/core/base/factory';
const tableProps = [ const tableProps = [
{ {
@@ -56,6 +59,10 @@ const tableProps = [
prop: 'name', prop: 'name',
label: '工段名称' label: '工段名称'
}, },
{
prop: 'factoryName',
label: '工厂'
},
{ {
prop: 'productionLineName', prop: 'productionLineName',
label: '产线' label: '产线'
@@ -99,8 +106,25 @@ export default {
} }
: undefined, : undefined,
].filter((v)=>v), ].filter((v)=>v),
listQuery: {
lineId: [],
},
tableData: [], tableData: [],
formConfig: [ formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'select',
label: '产线',
selectOptions: [],
param: 'lineId',
multiple: true,
},
{ {
type: 'input', type: 'input',
label: '工段名称', label: '工段名称',
@@ -146,14 +170,37 @@ export default {
components: { components: {
AddOrUpdate, AddOrUpdate,
}, },
created() {}, created() {
this.getPdLineList();
},
methods: { methods: {
getPdLineList() {
getPdList().then((res) => {
this.formConfig[1].selectOptions = res.data || [];
});
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
handleSearchBarChanged({ param, value }) {
this.listQuery.lineId = [];
this.$refs.searchBarForm.formInline.lineId = undefined;
getPdList(value).then((res) => {
this.formConfig[1].selectOptions = res.data || [];
});
},
buttonClick(val) { buttonClick(val) {
switch (val.btnName) { switch (val.btnName) {
case 'search': case 'search':
this.listQuery.pageNo = 1; this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10; this.listQuery.pageSize = 10;
this.listQuery.name = val.name; this.listQuery.name = val.name;
this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.lineId = val.lineId || [];
this.getDataList(); this.getDataList();
break; break;
case 'reset': case 'reset':

View File

@@ -1,8 +1,8 @@
<!-- <!--
* @Author: Do not edit * @Author: Do not edit
* @Date: 2023-08-29 14:59:29 * @Date: 2023-08-29 14:59:29
* @LastEditTime: 2023-10-16 15:10:42 * @LastEditTime: 2024-12-02 13:59:32
* @LastEditors: DY * @LastEditors: zwq
* @Description: * @Description:
--> -->
<template> <template>
@@ -92,7 +92,8 @@ const tableProps = [
}, },
{ {
prop: 'outputArea', prop: 'outputArea',
label: '产出面积/㎡' label: '产出面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ {
prop: 'lossNum', prop: 'lossNum',
@@ -100,11 +101,13 @@ const tableProps = [
}, },
{ {
prop: 'lossArea', prop: 'lossArea',
label: '损耗面积/㎡' label: '损耗面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ {
prop: 'lossRatio', prop: 'lossRatio',
label: '损耗比例%' label: '损耗比例%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
} }
]; ];
@@ -180,7 +183,6 @@ export default {
startPlaceholder: '开始时间', startPlaceholder: '开始时间',
endPlaceholder: '结束时间', endPlaceholder: '结束时间',
param: 'timeVal', param: 'timeVal',
defaultSelect: [],
width: 350 width: 350
}, },
{ {
@@ -312,8 +314,8 @@ export default {
this.listQuery.pageSize = 10; this.listQuery.pageSize = 10;
this.listQuery.lineId = val.line ? val.line : undefined; this.listQuery.lineId = val.line ? val.line : undefined;
this.listQuery.reportType = val.reportType ? val.reportType : undefined; this.listQuery.reportType = val.reportType ? val.reportType : undefined;
this.listQuery.reportStartTime = val.timeVal ? [new Date(val.timeVal[0]).getTime()] : undefined; this.listQuery.reportStartTime = val.timeVal ? [new Date(val.timeVal[0]).getTime(),new Date(val.timeVal[1]).getTime()] : undefined;
this.listQuery.reportEndTime = val.timeVal ? [new Date(val.timeVal[1]).getTime()] : undefined; //this.listQuery.reportEndTime = val.timeVal ? [new Date(val.timeVal[1]).getTime()] : undefined;
if (val.timeVal && val.timeVal.length > 0) { if (val.timeVal && val.timeVal.length > 0) {
this.fileName = val.timeVal[0].slice(0, 10) + '-' + val.timeVal[1].slice(0, 10) + '_' this.fileName = val.timeVal[0].slice(0, 10) + '-' + val.timeVal[1].slice(0, 10) + '_'
} }

View File

@@ -0,0 +1,169 @@
<template>
<div
:class="className"
:style="{ height: height, width: width, marginLeft: '10px' }" />
</template>
<script>
import * as echarts from 'echarts';
require('echarts/theme/macarons'); // echarts theme
import resize from '@/utils/chartMixins/resize';
const animationDuration = 1000;
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart',
},
title: {
type: String,
default: '',
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: '300px',
},
barData: {
type: Array,
default: () => [],
},
},
data() {
return {
chart: null,
targetId: '',
};
},
beforeDestroy() {
if (!this.chart) {
return;
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons');
const _this = this;
this.chart.setOption({
title: {
text: this.title
? '{space|}{tip|}{space|}{value|' + this.title + '}'
: '',
textStyle: {
rich: {
tip: {
width: 6,
height: 6,
borderRadius: 50,
backgroundColor: '#288AFF',
},
space: {
width: 8,
},
value: {
fontSize: 14,
color: 'black',
},
},
},
},
color: ['#288AFF', '#8EF0AB', '#FFDC94'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999',
},
},
},
legend: {
data: ['投入', '产出', '加工成品率'],
},
grid: {
containLabel: true,
},
xAxis: {
type: 'category',
data: this.barData.map((item) => {
return item.lineName;
}),
axisPointer: {
type: 'shadow',
},
},
yAxis: [
{
type: 'value',
name: '投入/产出 片',
min: 0,
axisLabel: {
formatter: '{value}',
},
},
{
type: 'value',
name: '加工成品率',
min: 0,
max: 100,
interval: 10,
axisLabel: {
formatter: '{value} %',
},
},
],
series: [
{
name: '投入',
type: 'bar',
barWidth: '20',
data: this.barData.map((item) => {
return item.inputNum;
}),
tooltip: {
valueFormatter: function (value) {
return value + ' 片';
},
},
animationDuration,
},
{
name: '产出',
type: 'bar',
barWidth: '20',
data: this.barData.map((item) => {
return item.outputNum;
}),
tooltip: {
valueFormatter: function (value) {
return value + ' 片';
},
},
animationDuration,
},
{
name: '加工成品率',
type: 'line',
yAxisIndex: 1,
tooltip: {
valueFormatter: function (value) {
return value + ' %';
},
},
data: this.barData.map((item) => {
return item.processingRatio;
}),
},
],
});
},
},
};
</script>

View File

@@ -0,0 +1,273 @@
<template>
<div class="baseTable">
<el-table
:ref="id"
:data="renderData"
v-bind="$attrs"
:border="cancelBorder ? false : true"
@current-change="currentChange"
@selection-change="handleSelectionChange"
style="width: 100%"
:header-cell-style="{
background: '#F2F4F9',
color: '#606266',
}">
<!-- 多选 -->
<el-table-column
v-if="selectWidth"
type="selection"
:width="selectWidth" />
<!-- 序号 -->
<el-table-column
v-if="page && limit"
prop="_pageIndex"
:width="pageWidth"
align="center"
:fixed="cancelPageFixed ? false : true">
<template slot="header">
<el-popover placement="bottom-start" width="300" trigger="click">
<div
class="setting-box"
style="max-height: 400px; overflow-y: auto">
<el-checkbox
v-for="(item, index) in tableProps"
:key="'cb' + index"
v-model="selectedBox[index]"
:label="item.label" />
</div>
<i slot="reference" class="el-icon-s-tools" />
</el-popover>
</template>
</el-table-column>
<el-table-column
v-for="item in renderTableHeadList"
:key="item.prop"
v-bind="item"
:label="item.label"
:prop="item.prop"
:fixed="item.fixed || false"
:show-overflow-tooltip="item.showOverflowtooltip || false"
:sortable="item.sortable || false">
<template slot="header">
<span>{{ item.label }}</span>
</template>
<!-- 多表头 -->
<template v-if="item.children">
<el-table-column
v-for="sub in item.children"
:prop="sub.prop"
:key="sub.prop"
v-bind="sub"
:label="sub.label">
<template v-if="sub.children">
<el-table-column
v-for="ssub in sub.children"
:prop="ssub.prop"
:key="ssub.prop"
v-bind="ssub"
:label="ssub.label">
<template slot-scope="sscopeInner">
<component
:is="ssub.subcomponent"
v-if="ssub.subcomponent"
:key="sscopeInner.row.id"
:inject-data="{ ...sscopeInner.row, ...ssub }"
@emitData="emitData" />
<span v-else>
{{ sscopeInner.row[ssub.prop] | commonFilter(ssub.filter) }}
</span>
</template>
</el-table-column>
</template>
<template slot-scope="scopeInner">
<component
:is="sub.subcomponent"
v-if="sub.subcomponent"
:key="scopeInner.row.id"
:inject-data="{ ...scopeInner.row, ...sub }"
@emitData="emitData" />
<span v-else>
{{ scopeInner.row[sub.prop] | commonFilter(sub.filter) }}
</span>
</template>
</el-table-column>
</template>
<template slot-scope="scope">
<component
:is="item.subcomponent"
v-if="item.subcomponent"
:key="scope.row.id"
:itemProp="item.prop"
:inject-data="{ ...scope.row, ...item }"
@emitData="emitData" />
<span v-else>
{{ scope.row[item.prop] | commonFilter(item.filter) }}
</span>
</template>
</el-table-column>
<slot name="handleBtn" />
</el-table>
<!-- 表格底部加号 -->
<el-button
v-if="addButtonShow"
class="addButton"
icon="el-icon-plus"
@click="emitButtonClick">
{{ addButtonShow }}
</el-button>
</div>
</template>
<script>
export default {
name: 'BaseTable',
filters: {
commonFilter: (source, filterType = (a) => a) => {
return filterType(source);
},
},
props: {
cancelBorder: {
type: Boolean,
default: false,
},
cancelPageFixed: {
type: Boolean,
default: false,
},
tableData: {
type: Array,
required: true,
default: () => {
return [];
},
},
tableProps: {
type: Array,
default: () => {
return [];
},
},
id: {
type: String,
required: false,
default: '',
},
page: {
type: Number,
required: false,
default: 0,
},
pageWidth: {
type: Number,
required: false,
default: 70,
},
limit: {
type: Number,
required: false,
default: 0,
},
selectWidth: {
type: Number,
required: false,
default: 0,
},
addButtonShow: {
type: String,
required: false,
default: '',
},
},
data() {
return {
selectedBox: new Array(100).fill(true),
};
},
computed: {
renderTableHeadList() {
return this.tableProps.filter((item, index) => {
return this.selectedBox[index];
});
},
renderData() {
return this.tableData.map((item, index) => {
return {
...item,
_pageIndex: (this.page - 1) * this.limit + index + 1,
};
});
},
},
beforeMount() {
this.selectedBox = new Array(100).fill(true);
},
methods: {
currentChange(newVal, oldVal) {
this.$emit('current-change', { newVal, oldVal });
},
handleSelectionChange(val) {
this.$emit('selection-change', val);
},
emitData(val) {
this.$emit('emitFun', val);
},
emitButtonClick() {
this.$emit('emitButtonClick');
},
setCurrent(name, index) {
let _this = this;
let obj = _this.$refs[name].data[index];
_this.$refs[name].setCurrentRow(obj);
},
doLayout(name) {
this.$refs[name].doLayout();
},
},
};
</script>
<style scoped>
.baseTable .show-col-btn {
margin-right: 5px;
line-height: inherit;
cursor: pointer;
}
.baseTable .el-icon-refresh {
cursor: pointer;
}
</style>
<style>
.baseTable .el-table__body tr.current-row > td.el-table__cell {
background-color: #eaf1fc;
}
.baseTable .el-table .el-table__cell {
padding: 0;
height: 35px;
}
.baseTable .addButton {
width: 100%;
height: 35px;
border-top: none;
color: #0b58ff;
border-color: #ebeef5;
border-radius: 0;
}
.baseTable .addButton:hover {
color: #0b58ff;
border-color: #ebeef5;
background-color: #fff;
}
.baseTable .addButton:focus {
border-color: #ebeef5;
background-color: #fff;
}
.el-tooltip__popper.is-dark {
background: rgba(0, 0, 0, 0.6) !important;
}
.el-tooltip__popper .popper__arrow,
.el-tooltip__popper .popper__arrow::after {
border-top-color: rgba(0, 0, 0, 0.4) !important;
}
</style>

View File

@@ -0,0 +1,314 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2024-12-02 13:43:57
* @LastEditors: zwq
* @Description:
-->
<template>
<div class="app-container">
<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="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" />
<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 { 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: 'proLineName',
label: '产线名称'
},
{
prop: 'inputNum',
label: '投入数量/片'
},
{
prop: 'outputNum',
label: '产出数量/片'
},
{
prop: 'outputArea',
label: '产出面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'lossNum',
label: '损耗数量/片'
},
{
prop: 'lossArea',
label: '损耗面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'lossRate',
label: '损耗比例%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}
];
export default {
data() {
return {
urlOptions: {
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',
label: '产线',
selectOptions: [],
param: 'line'
},
{
type: 'datePicker',
label: '时间范围',
dateType: 'datetimerange',
format: 'yyyy-MM-dd HH:mm:ss',
valueFormat: "yyyy-MM-ddTHH:mm:ss",
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'timeVal',
defaultSelect: [],
width: 350
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
}
],
};
},
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
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
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':
this.handleExport();
break;
default:
console.log(val);
}
},
// 获取数据列表
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then(response => {
this.tableData = response.data;
this.listQuery.total = response.data.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
}
},
};
</script>

View File

@@ -1,138 +1,304 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2023-10-16 15:18:23
* @LastEditors: DY
* @Description:
-->
<template> <template>
<div class="app-container"> <div>
<search-bar <div style="background: #f2f4f9; height: 40px; width: 100%">
:formConfigs="formConfig" <ButtonNav :menus="['当前', '历史']" @change="currentMenu" v-model="activeName">
ref="searchBarForm" <!-- <template v-slot:tab1>
@headBtnClick="buttonClick" /> <div>当前</div>
<base-table </template>
v-if="showData.length" <template v-slot:tab2>
class="right-aside" <div>历史</div>
v-loading="dataListLoading" </template> -->
:table-props="tableProps" </ButtonNav>
:page="listQuery.pageNo" </div>
:limit="listQuery.pageSize" <div class="app-container energyOverlimitLog">
:selectWidth="55" <div v-if="activeName === '历史' && routeType !== 'order'">
:table-data="showData" <!-- 搜索工作栏 -->
@selection-change="selectChange" <search-bar :formConfigs="formConfig" ref="searchBarForm" @select-changed="handleSearchBarChanged"
> @headBtnClick="buttonClick" />
<method-btn </div>
v-if="tableBtn.length" <h2 v-else>
slot="handleBtn" 订单名称:{{ name }}
:width="120" 订单编码:{{ code }}
label="操作" <el-button v-hasPermi="['base:core-work-order:export']" type="primary" @click="handleExport">导出</el-button>
:method-list="tableBtn" </h2>
@clickBtn="handleClick" /> <div v-show="activeName === '当前'"></div>
</base-table> <!-- 列表 -->
<div v-else class="no-data-bg"></div> <div v-if="activeName === '历史'">
<pagination <base-table-s :page="1" :limit="100" :table-props="tableProps" :table-data="tableData"
:limit.sync="listQuery.pageSize" :max-height="tableH / 2"></base-table-s>
:page.sync="listQuery.pageNo" <div v-if="listQuery.lineId.length !== 1 && tableData.length > 0">
:total="listQuery.total" <barChart style="margin-top: 50px" ref="barChart" height="600px" :bar-data="tableData" />
@pagination="getDataList" /> </div>
<el-dialog </div>
title="提示" <div v-if="activeName === '当前'">
:visible.sync="dialogVisible" <span class="blue-block"></span>
width="30%" <span class="tip">当班数据</span>
:before-close="handleClose"> <base-table-s :page="1" :limit="100" :table-props="tableProps" :table-data="tableData2"
<el-button type="primary" @click="exportXlsx">xlsx</el-button> :max-height="tableH / 2" />
<el-button type="success" @click="exportPdf">pdf</el-button> <span class="blue-block"></span>
<span slot="footer" class="dialog-footer"> <span class="tip">当天数据</span>
<el-button @click="dialogVisible = false"> </el-button> <base-table-s :page="1" :limit="100" :table-props="tableProps" :table-data="tableData3"
<el-button type="primary" @click="dialogVisible = false"> </el-button> :max-height="tableH / 2" />
</span> </div>
</el-dialog> </div>
</div> </div>
</template> </template>
<script> <script>
import { getPdlDataSearch, getPdList } from '@/api/core/monitoring/data' import {
import * as XLSX from 'xlsx' getPdlAutoReportNewSearch,
import FileSaver from 'file-saver' getPdlAutoReportNewSearchNow,
import jsPDF from 'jspdf' } from '@/api/core/monitoring/data';
import html2canvas from 'html2canvas' import { getPdList } from '@/api/core/monitoring/auto';
import { getFactoryPage } from '@/api/core/base/factory';
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
import ButtonNav from '@/components/ButtonNav';
import baseTableS from './baseTable.vue';
import barChart from './BarChart.vue';
import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';
const tableProps = [ const tableProps = [
{ {
prop: 'proLineName', prop: 'factoryName',
label: '产线名称' label: '工厂',
fixed: true
}, },
{ {
prop: 'inputNum', prop: 'lineName',
label: '投入数量/片' label: '产线',
fixed: true
}, },
{ {
prop: 'outputNum', prop: 'sizes',
label: '产出数量/片' label: '规格',
width: 105,
showOverflowtooltip: true,
fixed: true
}, },
{
prop: 'outputArea',
label: '产出面积/㎡'
},
{
prop: 'lossNum',
label: '损耗数量/片'
},
{
prop: 'lossArea',
label: '损耗面积/㎡'
},
{
prop: 'lossRate',
label: '损耗比例%'
}
];
{
prop: 'inputN',
label: '投入',
align: 'center',
children: [
{
prop: 'inputNum',
label: '投入数量/片',
},
{
prop: 'inputArea',
label: '投入面积/m²',
},
],
},
{
prop: 'outputN',
label: '产出',
align: 'center',
children: [
{
prop: 'outputNum',
label: '产出数量/片',
},
{
prop: 'outputArea',
label: '产出面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'lossN',
label: '不良',
align: 'center',
children: [
{
prop: 'lossNum',
label: '不良数量/片',
},
{
prop: 'lossArea',
label: '不良面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'lossRatio',
label: '不良率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'outputRatio',
label: '投入产出率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'processingRatio',
label: '加工成品率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'lossD',
label: '不良详情',
align: 'center',
children: [
{
prop: 'original',
label: '原片',
align: 'center',
children: [
{
prop: 'originalLossNum',
label: '原片不良/片',
},
{
prop: 'originalLossArea',
label: '原片不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'edge',
label: '磨边',
align: 'center',
children: [
{
prop: 'edgeLossNum',
label: '磨边不良/片',
},
{
prop: 'edgeLossArea',
label: '磨边不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'drill',
label: '打孔',
align: 'center',
children: [
{
prop: 'drillLossNum',
label: '打孔不良/片',
},
{
prop: 'drillLossArea',
label: '打孔不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'coating',
label: '镀膜',
align: 'center',
children: [
{
prop: 'coatingLossNum',
label: '镀膜不良/片',
},
{
prop: 'coatingLossArea',
label: '镀膜不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'silk',
label: '丝印',
align: 'center',
children: [
{
prop: 'silkLossNum',
label: '丝印不良/片',
},
{
prop: 'silkLossArea',
label: '丝印不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'tempering',
label: '钢化',
align: 'center',
children: [
{
prop: 'temperingLossNum',
label: '钢化不良/片',
},
{
prop: 'temperingLossArea',
label: '钢化不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'packing',
label: '包装',
align: 'center',
children: [
{
prop: 'packingLossNum',
label: '包装不良/片',
},
{
prop: 'packingLossArea',
label: '包装不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
],
},
];
export default { export default {
name: '',
mixins: [tableHeightMixin],
data() { data() {
return { return {
urlOptions: { urlOptions: {
getDataListURL: getPdlDataSearch getDataListURL: getPdlAutoReportNewSearch,
},
tableData: [],
listQuery: {
pageSize: 10,
pageNo: 1,
total: 1,
proLineId: undefined
}, },
exportLoading: false, routeType: 'line',
dataListLoading: false, code: '',
dialogVisible: false, name:'',
addOrEditTitle: '',
addOrUpdateVisible: false,
tableProps,
tableBtn: [],
showData: [],
tableData: [],
selectedList: [],
fileName: '',
formConfig: [ formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{ {
type: 'select', type: 'select',
label: '产线', label: '产线',
selectOptions: [], selectOptions: [],
param: 'line' param: 'lineId',
multiple: true,
defaultSelect:[]
}, },
{ {
type: 'datePicker', type: 'datePicker',
label: '时间范围', label: '时间范围',
dateType: 'datetimerange', dateType: 'daterange',
format: 'yyyy-MM-dd HH:mm:ss', format: 'yyyy-MM-dd',
valueFormat: "yyyy-MM-ddTHH:mm:ss", valueFormat: 'timestamp',
rangeSeparator: '-', rangeSeparator: '-',
startPlaceholder: '开始时间', startPlaceholder: '开始时间',
endPlaceholder: '结束时间', endPlaceholder: '结束时间',
param: 'timeVal', param: 'timeVal',
defaultSelect: [], defaultSelect:[],
width: 350 width: 350,
}, },
{ {
type: 'button', type: 'button',
btnName: '查询', btnName: '查询',
@@ -143,134 +309,78 @@ export default {
type: 'separate', type: 'separate',
}, },
{ {
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '', type: this.$auth.hasPermi('|base:core-work-order:export') ? 'button' : '',
type: 'button', // type: 'button',
btnName: '导出', btnName: '导出',
name: 'export', name: 'export',
color: 'warning', color: 'warning',
} },
], ],
listQuery: {
lineId: [],
},
activeName: '当前',
tableProps,
tableData: [],
tableData2: [],
tableData3: [],
}; };
}, },
created() { components: {
if (this.$route.params.startTime) { ButtonNav,
this.formConfig[1].defaultSelect = [this.$route.params.startTime, this.$route.params.endTime] baseTableS,
} barChart,
// const time = new Date()
// this.formConfig[1].defaultSelect = [time, time]
this.getDataList()
this.getPdLineList()
}, },
methods: { mounted() {
test() { this.getPdLineList()
var target = document.getElementsByClassName("right-aside")[0] this.$nextTick(() => {
target.style.background = '#FFFFFF' const tab = this.$route.query.tab; // 获取路由参数
var that = this console.log(this.$route.query);
setTimeout(() => { this.routeType = this.$route.query.buttonType === 'order' ? 'order' : 'line'
html2canvas(target).then(function(canvas) { this.code = this.$route.query.code
var contentWidth = canvas.width this.name = this.$route.query.name
var contentHeight = canvas.height
// 一页pdf显示html页面生成的canvas高度 if (tab === 'his') {
var pageHeight = contentHeight / 592.28 * 841.89 // 路由参数为 his 时,切换到“历史”标签
// 未生成pdf的html页面高度 this.activeName = '历史'; // 注意:这里直接传标签名('历史'),不是'his'
var leftHeight = contentHeight this.formConfig[1].defaultSelect = this.$route.query.lineId
// 页面偏移 this.formConfig[2].defaultSelect[0] = this.$route.query.startProduceTime
var position = 0 this.formConfig[2].defaultSelect[1] = this.$route.query.finishProduceTime
// a4纸的尺寸[595.28,841.89]html页面生成的canvas在pdf中图片的高度 // this.buttonClick()
var imgWidth = 595.28 this.listQuery.lineId = this.$route.query.lineId
var imgHeight = 592.28 / contentWidth * contentHeight } else {
this.activeName = '当前'; // 默认“当前”标签
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 methods: {
this.showData = this.tableData
},
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {});
},
getPdLineList() { getPdLineList() {
getPdList().then((res) => { getPdList().then((res) => {
this.formConfig[0].selectOptions = res.data || [] this.formConfig[1].selectOptions = res.data || [];
}) });
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
}, },
selectChange(val) {
console.log(val)
this.selectedList = val
},
buttonClick(val) { buttonClick(val) {
switch (val.btnName) { switch (val.btnName) {
case 'search': case 'search':
this.listQuery.pageNo = 1; this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.pageSize = 10; this.listQuery.lineId = val.lineId || [];
this.listQuery.proLineId = val.line ? val.line : undefined; this.listQuery.startTime = val.timeVal ? val.timeVal[0] : undefined;
this.listQuery.startTime = val.timeVal ? new Date(val.timeVal[0]).getTime() : undefined; this.listQuery.endTime = val.timeVal ? val.timeVal[1] : undefined;
this.listQuery.endTime = val.timeVal ? new Date(val.timeVal[1]).getTime() : undefined; if (this.activeName === '历史') {
if (val.timeVal && val.timeVal.length > 0) { this.getDataList();
this.fileName = val.timeVal[0].slice(0, 10) + '-' + val.timeVal[1].slice(0, 10) + '_' } else {
} this.getDataList2();
this.getDataList(); }
break; break;
case 'export': case 'export':
this.handleExport(); this.handleExport();
@@ -278,34 +388,265 @@ export default {
default: default:
console.log(val); console.log(val);
} }
},
// 获取数据列表
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then(response => {
this.tableData = response.data;
this.listQuery.total = response.data.length;
this.dataListLoading = false;
this.showData = this.tableData
});
}, },
// 每页数 currentMenu(val) {
sizeChangeHandle(val) { this.activeName = val; // 同步标签名到 activeName
this.listQuery.pageSize = val; let actualName = val === '历史' ? 'his' : 'now'; // 转换为内部状态
this.listQuery.pageNo = 1;
this.getDataList(); // 后续逻辑不变(根据 activeName 加载对应数据)
}, if (actualName === 'his') {
// 当前页 // this.$refs.searchBarForm.resetForm();
currentChangeHandle(val) { this.listQuery.factoryId = undefined;
this.listQuery.pageNo = val; if (!this.$route.query.lineId) {
this.getDataList(); this.listQuery.lineId = [];
},
handleExport() { }
if (this.selectedList.length > 0) { // 获取当前时间
this.showData = this.selectedList const now = new Date();
// 获取前一天的同一时间
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
// 设置为00:00:00
yesterday.setHours(0, 0, 0, 0);
// 设置为23:59:59
const end = new Date(yesterday.getTime());
end.setHours(23, 59, 59, 59);
this.listQuery.startTime = yesterday.getTime();
this.listQuery.endTime = end.getTime();
this.$nextTick(() => {
this.$refs.searchBarForm.formInline.timeVal = [
yesterday.getTime(),
end.getTime(),
];
});
this.getDataList();
} else {
this.getDataList2();
} }
this.dialogVisible = true },
}
getDataList() {
if (this.listQuery.startTime) {
this.dataListLoading = true;
// 判断是否为order类型且lineId有值
if (this.routeType === 'order' && this.listQuery.lineId?.length) {
// 存储所有接口请求的Promise
const requests = this.listQuery.lineId.map(lineId => {
// 复制原有查询参数替换当前lineId
const params = { ...this.listQuery, lineId: [lineId] };
return this.urlOptions.getDataListURL(params);
});
// 并行执行所有请求
Promise.all(requests)
.then(responses => {
// 合并所有接口返回的数据
this.tableData = responses.flatMap(response => {
return response.data.map(item => {
// 处理嵌套属性
item.originalLossNum = item.original?.lossNum;
item.originalLossArea = item.original?.lossArea;
item.edgeLossNum = item.edge?.lossNum;
item.edgeLossArea = item.edge?.lossArea;
item.drillLossNum = item.drill?.lossNum;
item.drillLossArea = item.drill?.lossArea;
item.coatingLossNum = item.coating?.lossNum;
item.coatingLossArea = item.coating?.lossArea;
item.silkLossNum = item.silk?.lossNum;
item.silkLossArea = item.silk?.lossArea;
item.temperingLossNum = item.tempering?.lossNum;
item.temperingLossArea = item.tempering?.lossArea;
item.packingLossNum = item.packing?.lossNum;
item.packingLossArea = item.packing?.lossArea;
return item;
});
});
this.$nextTick(() => {
if (this.tableData.length > 0) {
this.$refs.barChart.initChart();
}
});
})
.catch(error => {
console.error('接口请求失败:', error);
this.$message.error('数据加载失败,请重试');
})
.finally(() => {
this.dataListLoading = false;
});
} else {
// 非order类型或无lineId时正常单次请求
this.urlOptions.getDataListURL(this.listQuery)
.then(response => {
this.tableData = response.data.map((item, index) => {
item.originalLossNum = item.original?.lossNum;
item.originalLossArea = item.original?.lossArea;
item.edgeLossNum = item.edge?.lossNum;
item.edgeLossArea = item.edge?.lossArea;
item.drillLossNum = item.drill?.lossNum;
item.drillLossArea = item.drill?.lossArea;
item.coatingLossNum = item.coating?.lossNum;
item.coatingLossArea = item.coating?.lossArea;
item.silkLossNum = item.silk?.lossNum;
item.silkLossArea = item.silk?.lossArea;
item.temperingLossNum = item.tempering?.lossNum;
item.temperingLossArea = item.tempering?.lossArea;
item.packingLossNum = item.packing?.lossNum;
item.packingLossArea = item.packing?.lossArea;
return item;
});
this.$nextTick(() => {
if (this.tableData.length > 0) {
this.$refs.barChart.initChart();
}
});
})
.catch(error => {
console.error('接口请求失败:', error);
this.$message.error('数据加载失败,请重试');
})
.finally(() => {
this.dataListLoading = false;
});
}
} else {
this.$message.warning('请选择时间范围');
}
},
// 获取数据2列表
getDataList2() {
getPdlAutoReportNewSearchNow().then((response) => {
this.tableData2 = response.data.classData.map((item, index) => {
item.originalLossNum = item.original?.lossNum;
item.originalLossArea = item.original?.lossArea;
item.edgeLossNum = item.edge?.lossNum;
item.edgeLossArea = item.edge?.lossArea;
item.drillLossNum = item.drill?.lossNum;
item.drillLossArea = item.drill?.lossArea;
item.coatingLossNum = item.coating?.lossNum;
item.coatingLossArea = item.coating?.lossArea;
item.silkLossNum = item.silk?.lossNum;
item.silkLossArea = item.silk?.lossArea;
item.temperingLossNum = item.tempering?.lossNum;
item.temperingLossArea = item.tempering?.lossArea;
item.packingLossNum = item.packing?.lossNum;
item.packingLossArea = item.packing?.lossArea;
return item;
});
this.tableData3 = response.data.todayData.map((item, index) => {
item.originalLossNum = item.original?.lossNum;
item.originalLossArea = item.original?.lossArea;
item.edgeLossNum = item.edge?.lossNum;
item.edgeLossArea = item.edge?.lossArea;
item.drillLossNum = item.drill?.lossNum;
item.drillLossArea = item.drill?.lossArea;
item.coatingLossNum = item.coating?.lossNum;
item.coatingLossArea = item.coating?.lossArea;
item.silkLossNum = item.silk?.lossNum;
item.silkLossArea = item.silk?.lossArea;
item.temperingLossNum = item.tempering?.lossNum;
item.temperingLossArea = item.tempering?.lossArea;
item.packingLossNum = item.packing?.lossNum;
item.packingLossArea = item.packing?.lossArea;
return item;
});
});
},
handleSearchBarChanged({ param, value }) {
this.listQuery.lineId = [];
this.$refs.searchBarForm.formInline.lineId = undefined;
getPdList(value).then((res) => {
this.formConfig[1].selectOptions = res.data || [];
});
},
/** 导出按钮操作 */
handleExport() {
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);
exportTable.Sheets.Sheet1.A1.v = '序号' //导出表格第一列表头为序号
var exportTableOut = XLSX.write(exportTable, {
bookType: 'xlsx',
bookSST: true,
type: 'array',
});
// sheetjs.xlsx为导出表格的标题名称
try {
FileSaver.saveAs(
new Blob([exportTableOut], {
type: 'application/octet-stream',
}),
'产线统计数据.xlsx'
);
} catch (e) {
if (typeof console !== 'undefined') console.log(e, exportTableOut);
}
return exportTableOut;
},
}, },
}; };
</script> </script>
<style lang="scss">
.energyOverlimitLog {
.el-tabs__nav::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 2px;
background-color: #e4e7ed;
}
.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);
}
.searchBarBox {
margin-bottom: 0;
}
.blue-block {
float: left;
display: inline-block;
width: 4px;
height: 16px;
background-color: #0b58ff;
border-radius: 1px;
margin-right: 8px;
margin-top: 12px;
}
.tip {
display: inline-block;
font-size: 16px;
margin-right: 8px;
margin-top: 10px;
}
}
</style>

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: index.vue filename: index.vue
author: liubin author: liubin
date: 2023-08-04 14:44:58 date: 2023-08-04 14:44:58
@@ -16,6 +16,7 @@
v-if="tableData && tableData.length > 0" v-if="tableData && tableData.length > 0"
:table-props="tableProps" :table-props="tableProps"
:table-data="tableData" :table-data="tableData"
:max-height="tableH"
@emitFun="handleEmitFun" @emitFun="handleEmitFun"
/> />
</div> </div>
@@ -24,11 +25,13 @@
<script> <script>
import { getPdlDataOneDay } from '@/api/core/monitoring/data24' import { getPdlDataOneDay } from '@/api/core/monitoring/data24'
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
export default { export default {
name: 'productionLineData24', name: 'productionLineData24',
components: {}, components: {},
props: {}, props: {},
mixins: [tableHeightMixin],
data() { data() {
return { return {
urlOptions: { urlOptions: {
@@ -41,7 +44,7 @@ export default {
}, },
list: [], list: [],
arr: [], arr: [],
spanArr: [], spanArr: [],
timeList: [], timeList: [],
tableData: [], tableData: [],
tableProps: [], tableProps: [],
@@ -66,10 +69,14 @@ export default {
label: times.slice(0, 10) + ' ' + times.slice(11), label: times.slice(0, 10) + ' ' + times.slice(11),
align: 'center', align: 'center',
children: [ children: [
{ prop: times + '_in', label: '投入数量' }, { prop: times + '_in', label: '投入数量',
{ prop: times + '_out', label: '产出数量' }, filter: (val) => (val != null ? val.toFixed(2) : '-'), },
{ prop: times + '_junk', label: '报废数量' }, { prop: times + '_out', label: '产出数量',
{ prop: times + '_area', label: '产出面积' } filter: (val) => (val != null ? val.toFixed(2) : '-'), },
{ prop: times + '_junk', label: '报废数量',
filter: (val) => (val != null ? val.toFixed(2) : '-'), },
{ prop: times + '_area', label: '产出面积',
filter: (val) => (val != null ? val.toFixed(2) : '-'), }
] ]
} }
this.arr.push(subprop) this.arr.push(subprop)
@@ -168,7 +175,7 @@ export default {
// // console.log('recent-24', data); // // console.log('recent-24', data);
// this.initing = true; // this.initing = true;
// this.queryParams.pageSize = this.list.length; // this.queryParams.pageSize = this.list.length;
// setTimeout(() => { // setTimeout(() => {

View File

@@ -0,0 +1,273 @@
<template>
<div class="baseTable">
<el-table
:ref="id"
:data="renderData"
v-bind="$attrs"
:border="cancelBorder ? false : true"
@current-change="currentChange"
@selection-change="handleSelectionChange"
style="width: 100%"
:header-cell-style="{
background: '#F2F4F9',
color: '#606266',
}">
<!-- 多选 -->
<el-table-column
v-if="selectWidth"
type="selection"
:width="selectWidth" />
<!-- 序号 -->
<el-table-column
v-if="page && limit"
prop="_pageIndex"
:width="pageWidth"
align="center"
:fixed="cancelPageFixed ? false : true">
<template slot="header">
<el-popover placement="bottom-start" width="300" trigger="click">
<div
class="setting-box"
style="max-height: 400px; overflow-y: auto">
<el-checkbox
v-for="(item, index) in tableProps"
:key="'cb' + index"
v-model="selectedBox[index]"
:label="item.label" />
</div>
<i slot="reference" class="el-icon-s-tools" />
</el-popover>
</template>
</el-table-column>
<el-table-column
v-for="item in renderTableHeadList"
:key="item.prop"
v-bind="item"
:label="item.label"
:prop="item.prop"
:fixed="item.fixed || false"
:show-overflow-tooltip="item.showOverflowtooltip || false"
:sortable="item.sortable || false">
<template slot="header">
<span>{{ item.label }}</span>
</template>
<!-- 多表头 -->
<template v-if="item.children">
<el-table-column
v-for="sub in item.children"
:prop="sub.prop"
:key="sub.prop"
v-bind="sub"
:label="sub.label">
<template v-if="sub.children">
<el-table-column
v-for="ssub in sub.children"
:prop="ssub.prop"
:key="ssub.prop"
v-bind="ssub"
:label="ssub.label">
<template slot-scope="sscopeInner">
<component
:is="ssub.subcomponent"
v-if="ssub.subcomponent"
:key="sscopeInner.row.id"
:inject-data="{ ...sscopeInner.row, ...ssub }"
@emitData="emitData" />
<span v-else>
{{ sscopeInner.row[ssub.prop] | commonFilter(ssub.filter) }}
</span>
</template>
</el-table-column>
</template>
<template slot-scope="scopeInner">
<component
:is="sub.subcomponent"
v-if="sub.subcomponent"
:key="scopeInner.row.id"
:inject-data="{ ...scopeInner.row, ...sub }"
@emitData="emitData" />
<span v-else>
{{ scopeInner.row[sub.prop] | commonFilter(sub.filter) }}
</span>
</template>
</el-table-column>
</template>
<template slot-scope="scope">
<component
:is="item.subcomponent"
v-if="item.subcomponent"
:key="scope.row.id"
:itemProp="item.prop"
:inject-data="{ ...scope.row, ...item }"
@emitData="emitData" />
<span v-else>
{{ scope.row[item.prop] | commonFilter(item.filter) }}
</span>
</template>
</el-table-column>
<slot name="handleBtn" />
</el-table>
<!-- 表格底部加号 -->
<el-button
v-if="addButtonShow"
class="addButton"
icon="el-icon-plus"
@click="emitButtonClick">
{{ addButtonShow }}
</el-button>
</div>
</template>
<script>
export default {
name: 'BaseTable',
filters: {
commonFilter: (source, filterType = (a) => a) => {
return filterType(source);
},
},
props: {
cancelBorder: {
type: Boolean,
default: false,
},
cancelPageFixed: {
type: Boolean,
default: false,
},
tableData: {
type: Array,
required: true,
default: () => {
return [];
},
},
tableProps: {
type: Array,
default: () => {
return [];
},
},
id: {
type: String,
required: false,
default: '',
},
page: {
type: Number,
required: false,
default: 0,
},
pageWidth: {
type: Number,
required: false,
default: 70,
},
limit: {
type: Number,
required: false,
default: 0,
},
selectWidth: {
type: Number,
required: false,
default: 0,
},
addButtonShow: {
type: String,
required: false,
default: '',
},
},
data() {
return {
selectedBox: new Array(100).fill(true),
};
},
computed: {
renderTableHeadList() {
return this.tableProps.filter((item, index) => {
return this.selectedBox[index];
});
},
renderData() {
return this.tableData.map((item, index) => {
return {
...item,
_pageIndex: (this.page - 1) * this.limit + index + 1,
};
});
},
},
beforeMount() {
this.selectedBox = new Array(100).fill(true);
},
methods: {
currentChange(newVal, oldVal) {
this.$emit('current-change', { newVal, oldVal });
},
handleSelectionChange(val) {
this.$emit('selection-change', val);
},
emitData(val) {
this.$emit('emitFun', val);
},
emitButtonClick() {
this.$emit('emitButtonClick');
},
setCurrent(name, index) {
let _this = this;
let obj = _this.$refs[name].data[index];
_this.$refs[name].setCurrentRow(obj);
},
doLayout(name) {
this.$refs[name].doLayout();
},
},
};
</script>
<style scoped>
.baseTable .show-col-btn {
margin-right: 5px;
line-height: inherit;
cursor: pointer;
}
.baseTable .el-icon-refresh {
cursor: pointer;
}
</style>
<style>
.baseTable .el-table__body tr.current-row > td.el-table__cell {
background-color: #eaf1fc;
}
.baseTable .el-table .el-table__cell {
padding: 0;
height: 35px;
}
.baseTable .addButton {
width: 100%;
height: 35px;
border-top: none;
color: #0b58ff;
border-color: #ebeef5;
border-radius: 0;
}
.baseTable .addButton:hover {
color: #0b58ff;
border-color: #ebeef5;
background-color: #fff;
}
.baseTable .addButton:focus {
border-color: #ebeef5;
background-color: #fff;
}
.el-tooltip__popper.is-dark {
background: rgba(0, 0, 0, 0.6) !important;
}
.el-tooltip__popper .popper__arrow,
.el-tooltip__popper .popper__arrow::after {
border-top-color: rgba(0, 0, 0, 0.4) !important;
}
</style>

View File

@@ -0,0 +1,481 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2025-03-03 10:38:00
* @LastEditors: zwq
* @Description:
-->
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@select-changed="handleSearchBarChanged"
@headBtnClick="buttonClick" />
<base-table-s
v-if="showData.length"
class="right-aside"
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="showData"></base-table-s>
<div v-else class="no-data-bg"></div>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
</div>
</template>
<script>
import { parseTime } from '@/filter/code-filter';
import { getLineAuto, getPdList } from '@/api/core/monitoring/auto';
import { getFactoryPage } from '@/api/core/base/factory';
// import codeFilter from '../../mixins/code-filter'
import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';
import baseTableS from './baseTable.vue';
const tableProps = [
{
prop: 'reportType',
label: '报表类型',
fixed: true
},
{
prop: 'reportDate',
label: '日期',
width: 130,
fixed: true
},
{
prop: 'factoryName',
label: '工厂',
fixed: true
},
{
prop: 'lineName',
label: '产线',
fixed: true
},
{
prop: 'sizes',
label: '规格',
width: 105,
showOverflowtooltip: true,
fixed: true
},
{
prop: 'process',
label: '产品工艺',
fixed: true
},
{
prop: 'inputN',
label: '投入',
align: 'center',
children: [
{
prop: 'inputNum',
label: '投入数量/片',
},
{
prop: 'inputArea',
label: '投入面积/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'outputN',
label: '产出',
align: 'center',
children: [
{
prop: 'outputNum',
label: '产出数量/片',
},
{
prop: 'outputArea',
label: '产出面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'lossN',
label: '不良',
align: 'center',
children: [
{
prop: 'lossNum',
label: '不良数量/片',
},
{
prop: 'lossArea',
label: '不良面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'lossRatio',
label: '不良率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'outputRatio',
label: '投入产出率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'processingRatio',
label: '加工成品率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'lossD',
label: '不良详情',
align: 'center',
children: [
{
prop: 'original',
label: '原片',
align: 'center',
children: [
{
prop: 'originalLossNum',
label: '原片不良/片',
},
{
prop: 'originalLossArea',
label: '原片不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'edge',
label: '磨边',
align: 'center',
children: [
{
prop: 'edgeLossNum',
label: '磨边不良/片',
},
{
prop: 'edgeLossArea',
label: '磨边不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'drill',
label: '打孔',
align: 'center',
children: [
{
prop: 'drillLossNum',
label: '打孔不良/片',
},
{
prop: 'drillLossArea',
label: '打孔不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'coating',
label: '镀膜',
align: 'center',
children: [
{
prop: 'coatingLossNum',
label: '镀膜不良/片',
},
{
prop: 'coatingLossArea',
label: '镀膜不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'silk',
label: '丝印',
align: 'center',
children: [
{
prop: 'silkLossNum',
label: '丝印不良/片',
},
{
prop: 'silkLossArea',
label: '丝印不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'tempering',
label: '钢化',
align: 'center',
children: [
{
prop: 'temperingLossNum',
label: '钢化不良/片',
},
{
prop: 'temperingLossArea',
label: '钢化不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
{
prop: 'packing',
label: '包装',
align: 'center',
children: [
{
prop: 'packingLossNum',
label: '包装不良/片',
},
{
prop: 'packingLossArea',
label: '包装不良/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
],
},
];
export default {
components: {
baseTableS,
},
data() {
return {
urlOptions: {
getDataListURL: getLineAuto,
},
listQuery: {
lineId: [],
pageSize: 10,
pageNo: 1,
total: 1,
},
fileName: '',
dataListLoading: false,
tableProps,
tableBtn: [],
showData: [],
tableData: [],
formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'select',
label: '维度',
selectOptions: [
{
id: 1,
name: '日',
},
{
id: 2,
name: '周',
},
{
id: 3,
name: '月',
},
{
id: 4,
name: '年',
},
],
param: 'reportType',
},
{
type: 'select',
label: '产线',
selectOptions: [],
param: 'lineId',
},
{
type: 'datePicker',
label: '时间范围',
dateType: 'daterange',
format: 'yyyy-MM-dd',
valueFormat: 'timestamp',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'timeVal',
width: 350,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
},
],
};
},
created() {
// 获取当前时间
const now = new Date();
// 获取前一天的同一时间
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
// 设置为00:00:00
yesterday.setHours(0, 0, 0, 0);
// 设置为23:59:59
const end = new Date(yesterday.getTime());
end.setHours(23, 59, 59, 59);
this.listQuery.startTime = yesterday.getTime();
this.listQuery.endTime = end.getTime();
this.$nextTick(() => {
this.$refs.searchBarForm.formInline.timeVal = [
yesterday.getTime(),
end.getTime(),
];
});
this.getDataList();
this.getPdLineList();
},
methods: {
handleExport() {
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);
exportTable.Sheets.Sheet1.A1.v = '序号' //导出表格第一列表头为序号
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;
},
getPdLineList() {
getPdList().then((res) => {
this.formConfig[2].selectOptions = res.data || [];
});
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.lineId = val.lineId ? [val.lineId] : [];
this.listQuery.reportType = val.reportType || undefined;
this.listQuery.startTime = val.timeVal ? val.timeVal[0] : undefined;
this.listQuery.endTime = val.timeVal ? val.timeVal[1] : undefined;
this.getDataList();
break;
case 'export':
this.handleExport();
break;
default:
console.log(val);
}
},
// 获取数据列表
getDataList() {
this.dataListLoading = true;
const arr = ['日', '周', '月', '年'];
this.urlOptions.getDataListURL(this.listQuery).then((response) => {
this.tableData = response.data.list.map((item, index) => {
item.reportType = arr[item.reportType - 1];
item.originalLossNum = item.original?.lossNum;
item.originalLossArea = item.original?.lossArea;
item.edgeLossNum = item.edge?.lossNum;
item.edgeLossArea = item.edge?.lossArea;
item.drillLossNum = item.drill?.lossNum;
item.drillLossArea = item.drill?.lossArea;
item.coatingLossNum = item.coating?.lossNum;
item.coatingLossArea = item.coating?.lossArea;
item.silkLossNum = item.silk?.lossNum;
item.silkLossArea = item.silk?.lossArea;
item.temperingLossNum = item.tempering?.lossNum;
item.temperingLossArea = item.tempering?.lossArea;
item.packingLossNum = item.packing?.lossNum;
item.packingLossArea = item.packing?.lossArea;
return item;
});
this.listQuery.total = response.data.total;
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();
},
handleSearchBarChanged({ param, value }) {
this.listQuery.lineId = [];
this.$refs.searchBarForm.formInline.lineId = undefined;
getPdList(value).then((res) => {
this.formConfig[2].selectOptions = res.data || [];
});
},
},
};
</script>

View File

@@ -0,0 +1,366 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2025-02-26 16:42:12
* @LastEditors: zwq
* @Description:
-->
<template>
<div class="app-container">
<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"
:table-data="showData"></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>
</template>
<script>
import { parseTime } from '../../mixins/code-filter';
import { getProductAuto, getPdList } from '@/api/core/monitoring/auto';
import { listData } from '@/api/system/dict/data';
import { getFactoryPage } from '@/api/core/base/factory';
// import codeFilter from '../../mixins/code-filter'
import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';
const tableProps1 = [
{
prop: 'processType',
label: '工艺类型',
filter: (val) => (val === 1 ? '面板' : '背板'),
fixed: true
},
{
prop: 'reportType',
label: '报表类型',
fixed: true
},
{
prop: 'reportDate',
label: '日期',
width: 130,
fixed: true
},
{
prop: 'factoryName',
label: '工厂',
fixed: true
},
{
prop: 'process',
label: '产品工艺',
fixed: true
},
{
prop: 'all',
label: '合计',
align: 'center',
children: [
{
prop: 'inputArea',
label: '投入面积/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'outputArea',
label: '产出面积/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'lossArea',
label: '不良面积//m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'originalLossArea',
label: '原片不良/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'outputRatio',
label: '投入产出率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'processingRatio',
label: '加工成品率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
},
];
export default {
data() {
return {
urlOptions: {
getDataListURL: getProductAuto,
},
listQuery: {
pageSize: 10,
pageNo: 1,
total: 1,
},
fileName: '',
dataListLoading: false,
tableProps1,
tableProps: [],
tableBtn: [],
showData: [],
tableData: [],
formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'select',
label: '维度',
selectOptions: [
{
id: 1,
name: '日',
},
{
id: 2,
name: '周',
},
{
id: 3,
name: '月',
},
{
id: 4,
name: '年',
},
],
param: 'reportType',
},
{
type: 'select',
label: '产品工艺',
selectOptions: [],
param: 'process',
labelField: 'label',
valueField: 'label',
},
{
type: 'datePicker',
label: '时间范围',
dateType: 'daterange',
format: 'yyyy-MM-dd',
valueFormat: 'timestamp',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'timeVal',
width: 350,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
},
],
};
},
created() {
// 获取当前时间
const now = new Date();
// 获取前一天的同一时间
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
// 设置为00:00:00
yesterday.setHours(0, 0, 0, 0);
// 设置为23:59:59
const end = new Date(yesterday.getTime());
end.setHours(23, 59, 59, 59);
this.listQuery.startTime = yesterday.getTime();
this.listQuery.endTime = end.getTime();
this.$nextTick(() => {
this.$refs.searchBarForm.formInline.timeVal = [
yesterday.getTime(),
end.getTime(),
];
});
const queryParams = {
pageNo: 1,
pageSize: 99,
dictType: 'process_type',
};
listData(queryParams).then((response) => {
this.formConfig[2].selectOptions = response.data.list;
});
this.getDataList();
this.getPdLineList();
},
methods: {
handleExport() {
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);
exportTable.Sheets.Sheet1.A1.v = '序号' //导出表格第一列表头为序号
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;
},
getPdLineList() {
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.process = val.process || undefined;
this.listQuery.reportType = val.reportType || undefined;
this.listQuery.startTime = val.timeVal ? val.timeVal[0] : undefined;
this.listQuery.endTime = val.timeVal ? val.timeVal[1] : undefined;
this.getDataList();
break;
case 'export':
this.handleExport();
break;
default:
console.log(val);
}
},
// 获取数据列表
getDataList() {
this.dataListLoading = true;
const arr = ['日', '周', '月', '年'];
this.tableProps = [];
this.urlOptions.getDataListURL(this.listQuery).then((response) => {
if (response.data) {
let tableArr = [];
this.tableData = response.data?.list?.map((item, stop) => {
item.reportType = arr[item.reportType - 1];
if (stop === 0) {
item.lineDetList.forEach((prop, index) => {
item['inputArea' + index] = prop.inputArea;
item['outputArea' + index] = prop.outputArea;
item['lossArea' + index] = prop.lossArea;
item['originalLossArea' + index] = prop.originalLossArea;
item['outputRatio' + index] = prop.outputRatio;
item['processingRatio' + index] = prop.processingRatio;
const subprop = {
label: prop.lineName,
align: 'center',
children: [
{
prop: 'inputArea' + index,
label: '投入面积/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'outputArea' + index,
label: '产出面积/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'lossArea' + index,
label: '不良面积/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'originalLossArea' + index,
label: '原片不良/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'outputRatio' + index,
label: '投入产出率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'processingRatio' + index,
label: '加工成品率/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
],
};
tableArr.push(subprop);
});
}
return item;
});
this.tableProps.push(...this.tableProps1);
this.tableProps.splice(5, 0, ...tableArr);
this.listQuery.total = response.data.total;
}
this.listQuery.total = 0;
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();
},
},
};
</script>

View File

@@ -1,8 +1,8 @@
<!-- <!--
* @Author: Do not edit * @Author: Do not edit
* @Date: 2023-08-29 14:59:29 * @Date: 2023-08-29 14:59:29
* @LastEditTime: 2023-10-16 15:19:04 * @LastEditTime: 2024-12-02 13:44:47
* @LastEditors: DY * @LastEditors: zwq
* @Description: * @Description:
--> -->
<template> <template>
@@ -69,11 +69,13 @@ const tableProps = [
prop: 'reportStartTime', prop: 'reportStartTime',
label: '统计开始时间', label: '统计开始时间',
filter: parseTime, filter: parseTime,
width:160
}, },
{ {
prop: 'reportEndTime', prop: 'reportEndTime',
label: '统计结束时间', label: '统计结束时间',
filter: parseTime, filter: parseTime,
width:160
}, },
{ {
prop: 'lineName', prop: 'lineName',
@@ -93,7 +95,8 @@ const tableProps = [
}, },
{ {
prop: 'outputArea', prop: 'outputArea',
label: '产出面积/㎡' label: '产出面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ {
prop: 'lossNum', prop: 'lossNum',
@@ -101,11 +104,13 @@ const tableProps = [
}, },
{ {
prop: 'lossArea', prop: 'lossArea',
label: '损耗面积/㎡' label: '损耗面积/㎡',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ {
prop: 'lossRatio', prop: 'lossRatio',
label: '损耗比例%' label: '损耗比例%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
} }
]; ];
@@ -309,8 +314,8 @@ export default {
this.listQuery.lineId = val.line ? val.line : undefined; this.listQuery.lineId = val.line ? val.line : undefined;
this.listQuery.sectionId = val.section ? val.section : undefined; this.listQuery.sectionId = val.section ? val.section : undefined;
this.listQuery.reportType = val.reportType ? val.reportType : undefined; this.listQuery.reportType = val.reportType ? val.reportType : undefined;
this.listQuery.reportStartTime = val.timeVal ? [new Date(val.timeVal[0]).getTime()] : undefined; this.listQuery.reportStartTime = val.timeVal ? [new Date(val.timeVal[0]).getTime(),new Date(val.timeVal[1]).getTime()] : undefined;
this.listQuery.reportEndTime = val.timeVal ? [new Date(val.timeVal[1]).getTime()] : undefined; //this.listQuery.reportEndTime = val.timeVal ? [new Date(val.timeVal[1]).getTime()] : undefined;
if (val.timeVal && val.timeVal.length > 0) { if (val.timeVal && val.timeVal.length > 0) {
this.fileName = val.timeVal[0].slice(0, 10) + '-' + val.timeVal[1].slice(0, 10) + '_' this.fileName = val.timeVal[0].slice(0, 10) + '-' + val.timeVal[1].slice(0, 10) + '_'
} }

View File

@@ -14,8 +14,7 @@
:limit="listQuery.pageSize" :limit="listQuery.pageSize"
:selectWidth="55" :selectWidth="55"
:table-data="showData" :table-data="showData"
@selection-change="selectChange" @selection-change="selectChange" />
/>
<div v-else class="no-data-bg"></div> <div v-else class="no-data-bg"></div>
<pagination <pagination
:limit.sync="listQuery.pageSize" :limit.sync="listQuery.pageSize"
@@ -28,10 +27,12 @@
width="30%" width="30%"
:before-close="handleClose"> :before-close="handleClose">
<el-button type="primary" @click="exportXlsx">xlsx</el-button> <el-button type="primary" @click="exportXlsx">xlsx</el-button>
<el-button type="success" @click="exportPdf">pdf</el-button> <el-button type="success" @click="exportPdf">pdf</el-button>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="dialogVisible = false"> </el-button> <el-button type="primary" @click="dialogVisible = false">
</el-button>
</span> </span>
</el-dialog> </el-dialog>
</div> </div>
@@ -42,40 +43,43 @@
import { getSectionDataSearch } from '@/api/core/monitoring'; import { getSectionDataSearch } from '@/api/core/monitoring';
import { getProductionLinePage } from '@/api/core/base/productionLine'; import { getProductionLinePage } from '@/api/core/base/productionLine';
import { getWorkshopSectionPage } from '@/api/core/base/workshopSection'; import { getWorkshopSectionPage } from '@/api/core/base/workshopSection';
import * as XLSX from 'xlsx' import { parseTime } from '@/filter/code-filter';
import FileSaver from 'file-saver' import * as XLSX from 'xlsx';
import jsPDF from 'jspdf' import FileSaver from 'file-saver';
import html2canvas from 'html2canvas' import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
const tableProps = [ const tableProps = [
{ {
prop: 'proLineName', prop: 'proLineName',
label: '产线名称' label: '产线名称',
},
{
prop: 'sectionName',
label: '工段名称',
},
{
prop: 'inputNum',
label: '进片数量/片',
},
{
prop: 'outputNum',
label: '出片数量/片',
},
{
prop: 'lossNum',
label: '损耗数量/片',
},
{
prop: 'lossArea',
label: '损耗面积/m²',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
prop: 'lossRate',
label: '损耗比例/%',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{
prop: 'sectionName',
label: '工段名称'
},
{
prop: 'inputNum',
label: '进片数量/片'
},
{
prop: 'outputNum',
label: '出片数量/片'
},
{
prop: 'lossNum',
label: '损耗数量/片'
},
{
prop: 'lossArea',
label: '损耗面积/m²'
},
{
prop: 'lossRate',
label: '损耗比例/%'
}
]; ];
export default { export default {
@@ -83,29 +87,29 @@ export default {
data() { data() {
return { return {
urlOptions: { urlOptions: {
getDataListURL: getSectionDataSearch, getDataListURL: getSectionDataSearch,
}, },
tableProps, tableProps,
tableData: [], tableData: [],
showData: [], showData: [],
selectedList: [], selectedList: [],
listQuery: { listQuery: {
proLineId:undefined, proLineId: undefined,
sectionId: undefined, sectionId: undefined,
startTime: undefined, startTime: undefined,
endTime: undefined, endTime: undefined,
total: 0 total: 0,
}, },
dataListLoading: false, dataListLoading: false,
dialogVisible: false, dialogVisible: false,
fileName: [], fileName: [],
optionArrUrl: [getProductionLinePage, getWorkshopSectionPage], optionArrUrl: [getProductionLinePage, getWorkshopSectionPage],
formConfig: [ formConfig: [
{ {
type: 'select', type: 'select',
label: '产线', label: '产线',
selectOptions: [], selectOptions: [],
param: 'proLineId', param: 'proLineId',
defaultSelect: '', defaultSelect: '',
filterable: true, filterable: true,
onchange: true, onchange: true,
@@ -114,7 +118,7 @@ export default {
type: 'select', type: 'select',
label: '工段', label: '工段',
selectOptions: [], selectOptions: [],
param: 'sectionId', param: 'sectionId',
defaultSelect: '', defaultSelect: '',
filterable: true, filterable: true,
}, },
@@ -143,15 +147,21 @@ export default {
btnName: '导出', btnName: '导出',
name: 'export', name: 'export',
color: 'warning', color: 'warning',
} },
], ],
}; };
}, },
components: { components: {},
},
created() { created() {
this.getArr(); this.getArr();
// this.getDataList() const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 1);
this.listQuery.startTime = start.getTime();
this.listQuery.endTime = end.getTime();
this.formConfig[2].startPlaceholder = parseTime(start).substr(0, 10);
this.formConfig[2].endPlaceholder = parseTime(end).substr(0, 10);
this.getDataList();
}, },
methods: { methods: {
/** 根据产线获取工段 */ /** 根据产线获取工段 */
@@ -184,92 +194,96 @@ export default {
} }
}, },
test() { test() {
var target = document.getElementsByClassName("right-aside")[0] var target = document.getElementsByClassName('right-aside')[0];
target.style.background = '#FFFFFF' target.style.background = '#FFFFFF';
var that = this var that = this;
setTimeout(() => { setTimeout(() => {
html2canvas(target).then(function(canvas) { html2canvas(target).then(function (canvas) {
var contentWidth = canvas.width var contentWidth = canvas.width;
var contentHeight = canvas.height var contentHeight = canvas.height;
// 一页pdf显示html页面生成的canvas高度 // 一页pdf显示html页面生成的canvas高度
var pageHeight = contentHeight / 592.28 * 841.89 var pageHeight = (contentHeight / 592.28) * 841.89;
// 未生成pdf的html页面高度 // 未生成pdf的html页面高度
var leftHeight = contentHeight var leftHeight = contentHeight;
// 页面偏移 // 页面偏移
var position = 0 var position = 0;
// a4纸的尺寸[595.28,841.89]html页面生成的canvas在pdf中图片的高度 // a4纸的尺寸[595.28,841.89]html页面生成的canvas在pdf中图片的高度
var imgWidth = 595.28 var imgWidth = 595.28;
var imgHeight = 592.28 / contentWidth * contentHeight var imgHeight = (592.28 / contentWidth) * contentHeight;
var pageData = canvas.toDataURL('image/jpeg', 1.0) var pageData = canvas.toDataURL('image/jpeg', 1.0);
console.log('nihc URL', leftHeight, pageHeight) console.log('nihc URL', leftHeight, pageHeight);
var pdf = new jsPDF('', 'pt', 'a4') var pdf = new jsPDF('', 'pt', 'a4');
if (leftHeight < pageHeight) { if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 20, imgWidth, imgHeight) pdf.addImage(pageData, 'JPEG', 0, 20, imgWidth, imgHeight);
} else { } else {
while(leftHeight > 0) { while (leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight) pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
leftHeight -= pageHeight leftHeight -= pageHeight;
position -= 841.89 position -= 841.89;
// 避免空白页 // 避免空白页
if (leftHeight > 0) { if (leftHeight > 0) {
pdf.addPage() pdf.addPage();
}
} }
} }
}
pdf.save(that.fileName[0] + '-' + that.fileName[1] + '_工段统计.pdf') pdf.save(that.fileName[0] + '-' + that.fileName[1] + '_工段统计.pdf');
}) });
}, 300) }, 300);
}, },
exportECL() { exportECL() {
let tables = document.querySelector('.el-table').cloneNode(true) let tables = document.querySelector('.el-table').cloneNode(true);
const fix = tables.querySelector('.el-table__fixed') const fix = tables.querySelector('.el-table__fixed');
const fixRight = tables.querySelector('.el-table__fixed-right') const fixRight = tables.querySelector('.el-table__fixed-right');
if (fix) { if (fix) {
tables.removeChild(tables.querySelector('.el-table__fixed')) tables.removeChild(tables.querySelector('.el-table__fixed'));
} }
if (fixRight) { if (fixRight) {
tables.removeChild(tables.querySelector('.el-table__fixed-right')) tables.removeChild(tables.querySelector('.el-table__fixed-right'));
} }
let exportTable = XLSX.utils.table_to_book(tables) let exportTable = XLSX.utils.table_to_book(tables);
var exportTableOut = XLSX.write(exportTable, { var exportTableOut = XLSX.write(exportTable, {
bookType: 'xlsx', bookSST: true, type: 'array' bookType: 'xlsx',
}) bookSST: true,
// sheetjs.xlsx为导出表格的标题名称 type: 'array',
try { });
FileSaver.saveAs(new Blob([exportTableOut], { // sheetjs.xlsx为导出表格的标题名称
type: 'application/octet-stream' try {
}), this.fileName[0] + '-' + this.fileName[1] + '_工段统计.xlsx') FileSaver.saveAs(
} catch (e) { new Blob([exportTableOut], {
if (typeof console !== 'undefined') console.log(e, exportTableOut) type: 'application/octet-stream',
} }),
return exportTableOut this.fileName[0] + '-' + this.fileName[1] + '_工段统计.xlsx'
}, );
} catch (e) {
if (typeof console !== 'undefined') console.log(e, exportTableOut);
}
return exportTableOut;
},
exportPdf() { exportPdf() {
this.test() this.test();
setTimeout(() =>{ setTimeout(() => {
this.dialogVisible = false this.dialogVisible = false;
this.showData = this.tableData this.showData = this.tableData;
}, 600) }, 600);
}, },
exportXlsx() { exportXlsx() {
this.exportECL() this.exportECL();
this.dialogVisible = false this.dialogVisible = false;
this.showData = this.tableData this.showData = this.tableData;
}, },
handleClose(done) { handleClose(done) {
this.$confirm('确认关闭?') this.$confirm('确认关闭?')
.then(_ => { .then((_) => {
done(); done();
}) })
.catch(_ => {}); .catch((_) => {});
}, },
getArr() { getArr() {
const params = { const params = {
@@ -281,61 +295,63 @@ export default {
this.formConfig[index].selectOptions = response.data.list; this.formConfig[index].selectOptions = response.data.list;
}); });
}); });
}, },
getDataList() { getDataList() {
// this.listQuery.proLineId = '1672847052717821953'; this.urlOptions.getDataListURL(this.listQuery).then((res) => {
// this.listQuery.startTime = '1690626657000' this.tableData = res.data;
// this.listQuery.endTime = '1693564257000' this.listQuery.total = this.tableData.length;
this.urlOptions.getDataListURL(this.listQuery).then(res => { this.dataListLoading = false;
this.tableData = res.data
this.listQuery.total = this.tableData.length;
this.dataListLoading = false;
this.showData = this.tableData; this.showData = this.tableData;
}); });
}, },
// 每页数 // 每页数
sizeChangeHandle(val) { sizeChangeHandle(val) {
this.listQuery.pageSize = val; this.listQuery.pageSize = val;
this.listQuery.pageNo = 1; this.listQuery.pageNo = 1;
this.getDataList(); this.getDataList();
}, },
// 当前页 // 当前页
currentChangeHandle(val) { currentChangeHandle(val) {
this.listQuery.pageNo = val; this.listQuery.pageNo = val;
this.getDataList(); this.getDataList();
}, },
handleExport() { handleExport() {
if (this.selectedList.length > 0) { if (this.selectedList.length > 0) {
this.showData = this.selectedList this.showData = this.selectedList;
} }
this.dialogVisible = true this.dialogVisible = true;
}, },
selectChange(val) { selectChange(val) {
console.log(val) console.log(val);
this.selectedList = val this.selectedList = val;
}, },
buttonClick(val) { buttonClick(val) {
console.log(val) console.log(val);
switch (val.btnName) { switch (val.btnName) {
case 'search': case 'search':
console.log(val.timeSlot); console.log(val.timeSlot);
this.formConfig[2].startPlaceholder = '开始时间';
this.formConfig[2].endPlaceholder = '结束时间';
// this.listQuery.pageNo = 1; // this.listQuery.pageNo = 1;
// this.listQuery.pageSize = 10; // this.listQuery.pageSize = 10;
this.listQuery.proLineId = val.proLineId ? val.proLineId : undefined this.listQuery.proLineId = val.proLineId ? val.proLineId : undefined;
this.listQuery.sectionId = val.sectionId ? val.sectionId : undefined this.listQuery.sectionId = val.sectionId ? val.sectionId : undefined;
this.listQuery.startTime = val.timeSlot ? new Date(val.timeSlot[0]).getTime() : undefined this.listQuery.startTime = val.timeSlot
this.listQuery.endTime = val.timeSlot ? new Date(val.timeSlot[1]).getTime() : undefined ? new Date(val.timeSlot[0]).getTime()
: undefined;
this.listQuery.endTime = val.timeSlot
? new Date(val.timeSlot[1]).getTime()
: undefined;
if (val.timeSlot && val.timeSlot.length > 0) { if (val.timeSlot && val.timeSlot.length > 0) {
this.fileName[0] = val.timeSlot[0].slice(0, 10) this.fileName[0] = val.timeSlot[0].slice(0, 10);
this.fileName[1] = val.timeSlot[1].slice(0, 10) this.fileName[1] = val.timeSlot[1].slice(0, 10);
this.getDataList() this.getDataList();
} else { } else {
this.$message({ this.$message({
message: '请选择时间', message: '请选择时间',
type: 'warning' type: 'warning',
}); });
} }
break; break;
case 'reset': case 'reset':
this.$refs.searchBarForm.resetForm(); this.$refs.searchBarForm.resetForm();
@@ -349,12 +365,12 @@ export default {
case 'export': case 'export':
if (val.timeSlot && val.timeSlot.length > 0) { if (val.timeSlot && val.timeSlot.length > 0) {
this.handleExport(); this.handleExport();
} else { } else {
this.$message({ this.$message({
message: '请选择时间', message: '请选择时间',
type: 'warning' type: 'warning',
}); });
} }
break; break;
default: default:
console.log(val); console.log(val);

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: pieChart.vue filename: pieChart.vue
author: liubin author: liubin
date: 2023-09-06 15:02:49 date: 2023-09-06 15:02:49
@@ -10,7 +10,7 @@
<div <div
class="pie-chart" class="pie-chart"
ref="pieChart" ref="pieChart"
style="overflow: inherit;" style="overflow: inherit"
:data-eqname="value.equipmentName || 'Default'"></div> :data-eqname="value.equipmentName || 'Default'"></div>
<div class="data-view"> <div class="data-view">
<div class="data-view__item"> <div class="data-view__item">
@@ -64,7 +64,7 @@ export default {
}, },
subtext: '设备', //<========= subtext: '设备', //<=========
subtextStyle: { subtextStyle: {
fontSize: 14, fontSize: 13,
}, },
}, },
color: ['#3da8fd', '#8ef0ab', '#6b5cfd', '#FFC72A', 'transparent'], color: ['#3da8fd', '#8ef0ab', '#6b5cfd', '#FFC72A', 'transparent'],
@@ -194,22 +194,31 @@ export default {
mttr, mttr,
} = item; } = item;
this.config.title.text = lineName; this.config.title.text = lineName;
this.config.title.subtext = equipmentName; // 找到第一个 '-' 的位置
let firstDashIndex = equipmentName.indexOf('-');
// 找到第二个 '-' 的位置
let secondDashIndex = equipmentName.indexOf('-', firstDashIndex + 1);
// 截取第二个 '-' 后面的字符串
let result = equipmentName.substring(secondDashIndex + 1);
this.config.title.subtext = result ? result : '-';
this.config.series[0].data = [ this.config.series[0].data = [
{ name: '工作时长', value: workTime }, { name: '工作时长', value: workTime ? workTime.toFixed(2) : '0.00' },
{ name: '停机时长', value: stopTime }, { name: '停机时长', value: stopTime ? stopTime.toFixed(2) : '0.00' },
{ name: '故障时长', value: downTime }, { name: '故障时长', value: downTime ? downTime.toFixed(2) : '0.00' },
]; ];
this.config.series[1].data = [ this.config.series[1].data = [
{ name: '速度开动率', value: peEfficiency }, {
name: '速度开动率',
value: peEfficiency ? peEfficiency.toFixed(2) : '0.00',
},
{ name: '', value: Math.ceil(peEfficiency) - peEfficiency }, { name: '', value: Math.ceil(peEfficiency) - peEfficiency },
]; ];
//
this.textData = { this.textData = {
workTime: +workTime.toFixed(2), workTime: workTime ? workTime.toFixed(2) : '0.00',
stopTime: +stopTime.toFixed(2), stopTime: stopTime ? stopTime.toFixed(2) : '0.00',
downTime: +downTime.toFixed(2), downTime: downTime ? downTime.toFixed(2) : '0.00',
peEfficiency: +peEfficiency.toFixed(2), peEfficiency: peEfficiency ? peEfficiency.toFixed(2) : '0.00',
}; };
}, },
}, },

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: index.vue filename: index.vue
author: liubin author: liubin
date: 2023-09-04 09:34:52 date: 2023-09-04 09:34:52
@@ -25,8 +25,9 @@
class="base-table__margin" class="base-table__margin"
:table-props="tableProps" :table-props="tableProps"
:page="1" :page="1"
:limit="10" :limit="999"
:table-data="list" :table-data="list"
:max-height="tableH"
@emitFun="handleEmitFun"></base-table> @emitFun="handleEmitFun"></base-table>
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane
@@ -88,11 +89,13 @@
<script> <script>
// import moment from 'moment'; // import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin'; import basicPageMixin from '@/mixins/lb/basicPageMixin';
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
import PieChart from './components/pieChart.vue'; import PieChart from './components/pieChart.vue';
import { parseTime } from '@/filter/code-filter';
export default { export default {
name: 'EfficiencyAnalysis', name: 'EfficiencyAnalysis',
mixins: [basicPageMixin], mixins: [basicPageMixin, tableHeightMixin],
components: { PieChart }, components: { PieChart },
props: {}, props: {},
data() { data() {
@@ -118,8 +121,18 @@ export default {
tableProps: [ tableProps: [
{ prop: 'factoryName', label: '工厂' }, { prop: 'factoryName', label: '工厂' },
{ prop: 'lineName', label: '产线' }, { prop: 'lineName', label: '产线' },
{ prop: 'sectionName', label: '工段' }, {
{ prop: 'equipmentName', label: '设备' }, prop: 'sectionName',
width: 120,
showOverflowtooltip: true,
label: '工段',
},
{
prop: 'equipmentName',
width: 150,
showOverflowtooltip: true,
label: '设备',
},
{ {
label: '有效时间', label: '有效时间',
children: [ children: [
@@ -127,12 +140,13 @@ export default {
width: 128, width: 128,
prop: 'workTime', prop: 'workTime',
label: '工作时长[h]', label: '工作时长[h]',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ {
width: 128, width: 128,
prop: 'workRate', prop: 'workRate',
label: '百分比[%]', label: '百分比[%]',
filter: (val) => (val != null ? +val.toFixed(3) : '-'), filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
], ],
}, },
@@ -143,8 +157,14 @@ export default {
width: 128, width: 128,
prop: 'stopTime', prop: 'stopTime',
label: '停机时长[h]', label: '停机时长[h]',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
width: 128,
prop: 'stopRate',
label: '百分比[%]',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ width: 128, prop: 'stopRate', label: '百分比[%]' },
], ],
}, },
{ {
@@ -154,14 +174,19 @@ export default {
width: 128, width: 128,
prop: 'downTime', prop: 'downTime',
label: '故障时长[h]', label: '故障时长[h]',
filter: (val) => (val != null ? +val.toFixed(3) : '-'), filter: (val) => (val != null ? val.toFixed(2) : '-'),
},
{
width: 128,
prop: 'downRate',
label: '百分比[%]',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ width: 128, prop: 'downRate', label: '百分比[%]' },
{ {
width: 128, width: 128,
prop: 'timeEfficiency', prop: 'timeEfficiency',
label: '时间开动率', label: '时间开动率',
filter: (val) => (val != null ? +val.toFixed(3) : '-'), filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
], ],
}, },
@@ -172,29 +197,31 @@ export default {
width: 128, width: 128,
prop: 'realProcSpeed', prop: 'realProcSpeed',
label: '实际加工速度', label: '实际加工速度',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ {
width: 128, width: 128,
prop: 'designProcSpeed', prop: 'designProcSpeed',
label: '理论加工速度', label: '理论加工速度',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ {
width: 128, width: 128,
prop: 'peEfficiency', prop: 'peEfficiency',
label: '速度开动率', label: '速度开动率',
filter: (val) => (val != null ? +val.toFixed(3) : '-'), filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
], ],
}, },
{ // {
prop: 'oee', // prop: 'oee',
label: 'OEE', // label: 'OEE',
filter: (val) => (val != null ? +val.toFixed(3) : '-'), // filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, // },
{ {
prop: 'teep', prop: 'teep',
label: 'TEEP', label: '设备生产能效比例',
filter: (val) => (val != null ? +val.toFixed(3) : '-'), filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
// { // {
// _action: 'view-trend', // _action: 'view-trend',
@@ -324,6 +351,20 @@ export default {
}; };
}, },
created() { created() {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 1);
this.queryParams.recordTime[0] =
parseTime(start).substr(0, 10) + ' 00:00:00';
this.queryParams.recordTime[1] = parseTime(end).substr(0, 10) + ' 00:00:00';
this.$nextTick(() => {
this.searchBarFormConfig[2].extraOptions[0].startPlaceholder = parseTime(
start
).substr(0, 10);
this.searchBarFormConfig[2].extraOptions[0].endPlaceholder = parseTime(
end
).substr(0, 10);
});
this.getFactory(); this.getFactory();
this.getLine(); this.getLine();
this.getList(); this.getList();
@@ -374,6 +415,7 @@ export default {
/** 查询列表 */ /** 查询列表 */
async getList() { async getList() {
this.loading = true; this.loading = true;
this.list = [];
const { code, data } = await this.$axios({ const { code, data } = await this.$axios({
url: '/analysis/equipment-analysis/efficiency', url: '/analysis/equipment-analysis/efficiency',
method: 'get', method: 'get',
@@ -385,7 +427,6 @@ export default {
}, },
handleSearchBarBtnClick({ btnName, ...payload }) { handleSearchBarBtnClick({ btnName, ...payload }) {
console.log('handleSearchBarBtnClick', btnName, payload);
if (btnName == 'visualization') { if (btnName == 'visualization') {
// 可视化 // 可视化
this.visualizationOpen = true; this.visualizationOpen = true;
@@ -395,12 +436,26 @@ export default {
this.queryParams.factoryId = payload.factoryId || null; this.queryParams.factoryId = payload.factoryId || null;
this.queryParams.lineId = payload.lineId || null; this.queryParams.lineId = payload.lineId || null;
if (0 == payload.dateFilterType) { if (0 == payload.dateFilterType) {
this.queryParams.recordTime = payload.timerange; if (payload.timerange) {
this.searchBarFormConfig[2].extraOptions[0].startPlaceholder =
'开始时间';
this.searchBarFormConfig[2].extraOptions[0].endPlaceholder =
'结束时间';
this.queryParams.recordTime = payload.timerange;
}
} else if (1 == payload.dateFilterType) { } else if (1 == payload.dateFilterType) {
this.queryParams.recordTime = [ this.searchBarFormConfig[2].extraOptions[0].startPlaceholder =
`${payload.timeday} 00:00:00`, '开始时间';
`${payload.timeday} 23:59:59`, this.searchBarFormConfig[2].extraOptions[0].endPlaceholder =
]; '结束时间';
if (payload.timeday) {
this.queryParams.recordTime = [
`${payload.timeday} 00:00:00`,
`${payload.timeday} 23:59:59`,
];
} else {
this.queryParams.recordTime = null;
}
} }
} else { } else {
this.queryParams.recordTime = null; this.queryParams.recordTime = null;

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: index.vue filename: index.vue
author: liubin author: liubin
date: 2023-09-04 09:34:52 date: 2023-09-04 09:34:52
@@ -19,6 +19,7 @@
:page="queryParams.pageNo" :page="queryParams.pageNo"
:limit="queryParams.pageSize" :limit="queryParams.pageSize"
:table-data="list" :table-data="list"
:max-height="tableH"
@emitFun="handleEmitFun"> @emitFun="handleEmitFun">
<!-- <method-btn <!-- <method-btn
v-if="tableBtn.length" v-if="tableBtn.length"
@@ -41,10 +42,11 @@
<script> <script>
import moment from 'moment'; import moment from 'moment';
import basicPageMixin from '@/mixins/lb/basicPageMixin'; import basicPageMixin from '@/mixins/lb/basicPageMixin';
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
export default { export default {
name: 'ExceptionAnalysis', name: 'ExceptionAnalysis',
mixins: [basicPageMixin], mixins: [basicPageMixin, tableHeightMixin],
components: {}, components: {},
props: {}, props: {},
data() { data() {
@@ -82,14 +84,18 @@ export default {
width: 240, width: 240,
prop: 'mtbf', prop: 'mtbf',
label: '平均故障间隔时间[MTBF](h)', label: '平均故障间隔时间[MTBF](h)',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ {
width: 240, width: 240,
prop: 'mttr', prop: 'mttr',
label: '平均维修时间[MTTR](h)', label: '平均维修时间[MTTR](h)',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
{ width: 128, prop: 'workTime', label: '工作时长(h)' }, { width: 128, prop: 'workTime', label: '工作时长(h)',
{ width: 128, prop: 'downTime', label: '故障时长(h)' }, filter: (val) => (val != null ? val.toFixed(2) : '-'), },
{ width: 128, prop: 'downTime', label: '故障时长(h)',
filter: (val) => (val != null ? val.toFixed(2) : '-'), },
{ prop: 'downCount', label: '故障次数' }, { prop: 'downCount', label: '故障次数' },
], ],
searchBarFormConfig: [ searchBarFormConfig: [

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
<!-- <!--
filename: lineChart.vue filename: lineChart.vue
author: liubin author: liubin
date: 2023-09-04 13:45:00 date: 2023-09-04 13:45:00
description: description:
--> -->
<template> <template>
@@ -11,6 +11,7 @@
<script> <script>
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import edata from './data';
export default { export default {
name: 'LineChart', name: 'LineChart',
@@ -43,7 +44,7 @@ export default {
eq.okQuantity, eq.okQuantity,
eq.nokQuantity, eq.nokQuantity,
eq.totalQuantity, eq.totalQuantity,
eq.passRate?.toFixed(4), typeof eq.passRate === "number" ? eq.passRate.toFixed(4) : "0.0000"
]); ]);
}); });
return { return {

View File

@@ -1,4 +1,4 @@
<!-- <!--
filename: index.vue filename: index.vue
author: liubin author: liubin
date: 2023-09-04 09:34:52 date: 2023-09-04 09:34:52
@@ -26,6 +26,7 @@
:page="queryParams.pageNo" :page="queryParams.pageNo"
:limit="queryParams.pageSize" :limit="queryParams.pageSize"
:table-data="list" :table-data="list"
:max-height="tableH"
@emitFun="handleEmitFun"></base-table> @emitFun="handleEmitFun"></base-table>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="'\u3000柱状图\u3000'" name="graph"> <el-tab-pane :label="'\u3000柱状图\u3000'" name="graph">
@@ -47,10 +48,13 @@
<script> <script>
import moment from 'moment'; import moment from 'moment';
import LineChart from './components/lineChart.vue'; import LineChart from './components/lineChart.vue';
import { parseTime } from '@/filter/code-filter';
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
export default { export default {
name: 'QualityAnalysis', name: 'QualityAnalysis',
components: { LineChart }, components: { LineChart },
mixins: [tableHeightMixin],
props: {}, props: {},
data() { data() {
const now = new Date(); const now = new Date();
@@ -92,24 +96,6 @@ export default {
endPlaceholder: '结束日期', endPlaceholder: '结束日期',
defaultTime: ['00:00:00', '23:59:59'], defaultTime: ['00:00:00', '23:59:59'],
param: 'recordTime', param: 'recordTime',
defaultSelect: [
new Date(y, m, d)
.toLocaleString()
.split('/')
.map((item, index) => {
if (index == 1 || index == 2) return item.padStart(2, '0');
return item;
})
.join('-'),
new Date(y, m, d, 23, 59, 59)
.toLocaleString()
.split('/')
.map((item, index) => {
if (index == 1 || index == 2) return item.padStart(2, '0');
return item;
})
.join('-'),
],
}, },
{ {
type: 'button', type: 'button',
@@ -156,22 +142,23 @@ export default {
{ {
// width: 160, // width: 160,
prop: 'inQuantity', prop: 'inQuantity',
label: '进片数量', label: '进片数量[片]',
}, },
{ {
// width: 160, // width: 160,
prop: 'outQuantity', prop: 'outQuantity',
label: '出片数量', label: '出片数量[片]',
}, },
{ {
// width: 160, // width: 160,
prop: 'nokQuantity', prop: 'nokQuantity',
label: '破损/不合格数', label: '破损/不合格数[片]',
}, },
{ {
// width: 160, // width: 160,
prop: 'passRate', prop: 'passRate',
label: '合格率', label: '合格率',
filter: (val) => (val != null ? val.toFixed(2) : '-'),
}, },
], ],
lineChartConfig: { lineChartConfig: {
@@ -248,11 +235,23 @@ export default {
}, },
computed: {}, computed: {},
created() { created() {
const end = new Date();
const start = new Date();
this.queryParams.recordTime = [
parseTime(start).substr(0, 10) + ' 00:00:00',
parseTime(end).substr(0, 10) + ' 23:59:59',
];
this.searchBarFormConfig[2].startPlaceholder = parseTime(start).substr(
0,
10
);
this.searchBarFormConfig[2].endPlaceholder = parseTime(end).substr(0, 10);
this.fillLineOptions(); this.fillLineOptions();
this.fillProductOptions(); this.fillProductOptions();
this.getList();
}, },
mounted() { mounted() {
this.$refs['search-bar'].headBtnClick('search'); //this.$refs['search-bar'].headBtnClick('search');
}, },
methods: { methods: {
handleTabClick(tab, event) { handleTabClick(tab, event) {
@@ -316,6 +315,8 @@ export default {
// debugger; // debugger;
switch (btn.btnName) { switch (btn.btnName) {
case 'search': case 'search':
this.searchBarFormConfig[2].startPlaceholder = '开始时间';
this.searchBarFormConfig[2].endPlaceholder = '结束时间';
this.queryParams.lineId = btn.lineId; this.queryParams.lineId = btn.lineId;
this.queryParams.productId = btn.productId; this.queryParams.productId = btn.productId;
this.queryParams.recordTime = btn.recordTime this.queryParams.recordTime = btn.recordTime

View File

@@ -1,8 +1,15 @@
<!-- <!--
* @Author: zwq
* @Date: 2024-10-29 09:47:40
* @LastEditors: zwq
* @LastEditTime: 2024-11-26 14:41:52
* @Description:
-->
<!--
filename: lineChart.vue filename: lineChart.vue
author: liubin author: liubin
date: 2023-09-04 13:45:00 date: 2023-09-04 13:45:00
description: description:
--> -->
<template> <template>
@@ -32,6 +39,12 @@ export default {
mounted() { mounted() {
this.init(); this.init();
}, },
activated() {
// 由于给echart添加了resize事件, 在组件激活时需要重新resize绘画一次, 否则出现空白bug
if (this.chart) {
this.echart.resize();
}
},
beforeDestroy() { beforeDestroy() {
if (this.chart) { if (this.chart) {
this.chart.dispose(); this.chart.dispose();
@@ -43,7 +56,10 @@ export default {
this.setOption(this.config); this.setOption(this.config);
}, },
setOption(option) { setOption(option) {
if (this.chart) this.chart.setOption(option); if (this.chart) this.chart.setOption(option,true);
window.addEventListener("resize", () => {
this.chart.resize();
});
}, },
}, },
}; };

View File

@@ -144,28 +144,18 @@ export default {
eqList: [], eqList: [],
graphList: [], graphList: [],
templateConfig: { templateConfig: {
color: [
'#283D68',
'#FFB61F',
'#4481FF',
'#5AD8A6',
'#E97466',
'#ccc', //<=== 需按情况更新
'#ccc',
'#ccc',
'#ccc',
'#ccc',
],
grid: { grid: {
top: 48, top: 48,
left: 48, left: 48,
right: 24, right: 90,
bottom: 24, bottom: 24,
}, },
legend: { legend: {
top: 0, type: 'scroll',
right: 12, orient: 'vertical',
padding: 6, right: 10,
top: 20,
bottom: 20,
itemWidth: 16, itemWidth: 16,
itemHeight: 8, itemHeight: 8,
itemGap: 20, itemGap: 20,
@@ -495,6 +485,7 @@ export default {
return; return;
} }
this.graphList.push(...newEqlist); this.graphList.push(...newEqlist);
this.templateConfig.series = [];
newEqlist.forEach(this.setSeries); newEqlist.forEach(this.setSeries);
} }
this.open = false; this.open = false;

View File

@@ -86,7 +86,7 @@ export default class GanttGraph {
<span class="eq-name" style="margin-left: 4px;">${params.seriesName}</span> <span class="eq-name" style="margin-left: 4px;">${params.seriesName}</span>
</div> </div>
<span class="run-status" style="margin-left: 8px; opacity: 0.6">${params.name}</span> <span class="run-status" style="margin-left: 8px; opacity: 0.6">${params.name}</span>
</div> </div>
` `
} }
} }
@@ -112,7 +112,7 @@ export default class GanttGraph {
// top: 12 + 128 * this.gridIndex, // top: 12 + 128 * this.gridIndex,
top: 12 + 104 * this.gridIndex, top: 12 + 104 * this.gridIndex,
right: 48, right: 48,
left: 88, left: 100,
height: 56 height: 56
} }
} }
@@ -175,7 +175,7 @@ export default class GanttGraph {
nameGap: 14, nameGap: 14,
nameRotate: 0, nameRotate: 0,
nameTextStyle: { nameTextStyle: {
fontSize: 16, fontSize: 12,
color: '#000A' color: '#000A'
}, },
axisLine: { axisLine: {
@@ -325,4 +325,4 @@ export default class GanttGraph {
console.log(JSON.stringify(this.option, null, 2)); console.log(JSON.stringify(this.option, null, 2));
} }
} }

View File

@@ -0,0 +1,302 @@
import * as echarts from 'echarts'
function getStartTime(timestamp) {
return new Date(new Date(timestamp).toLocaleDateString()).getTime();
}
function renderItem(params, api) {
var categoryIndex = api.value(0);
var start = api.coord([api.value(1), categoryIndex]);
var end = api.coord([api.value(2), categoryIndex]);
var height = api.size([0, 1])[1] * 0.5;
var rectShape = echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height,
},
{
x: params.coordSys.x,
y: params.coordSys.y - 16,
width: params.coordSys.width,
height: params.coordSys.height,
}
);
return (
rectShape && {
type: 'rect',
transition: ['shape'],
shape: rectShape,
style: api.style(),
}
);
}
// unused
function getXaxisRange(startTime) {
return Array(24)
.fill(startTime)
.map((item, index) => {
return new Date(item + index * 3600 * 1000)
.toLocaleTimeString()
.split(':')
.slice(0, 2)
.join(':');
});
}
function getTodayStart(today) {
const [y, m, d] = [
today.getFullYear(),
today.getMonth(),
today.getDate(),
];
// debugger;
return new Date(y, m, d).getTime();
}
/** 颜色配置 */
const types = [
{ name: '运行', color: '#288AFF' },
{ name: '计划停机', color: '#FFDC94' },
{ name: '故障', color: '#FC9C91' },
{ name: '空白', color: '#F2F4F9' },
];
export default class GanttGraph {
// tooltip - 基本是固定的
tooltip = {
trigger: 'item',
axisPointer: {
type: 'none',
},
formatter: (params) => {
// debugger;
return `
<div style="display: flex; flex-direction: column;">
<span>${new Date(params.value[1]).toLocaleTimeString()} ~ ${new Date(params.value[2]).toLocaleTimeString()}</span>
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="display: flex; align-items: center;">
<span class="icon" style="width: 8px; height: 8px; border-radius: 2px; background: ${params.color}"></span>
<span class="eq-name" style="margin-left: 4px;">${params.data.showName}</span>
</div>
<span class="run-status" style="margin-left: 8px; opacity: 0.6">${params.name}</span>
</div>
`
}
}
grid = []
xAxis = []
yAxis = []
series = []
constructor(el, startTime) {
this.el = el;
this.startTime = new Date(startTime);
// this.startTime = new Date(new Date('2023/10/8').toLocaleDateString());
// console.log('<> Gantt Created', this.startTime);
}
// 构造一个新的 grid
makeGrid() {
return {
top: 0,
right: 20,
left: 100,
bottom: 50,
}
}
// 构造一个 xAxis
makeXaxis() {
return [
{
axisTick: {
alignWithLabel: true,
inside: true,
},
type: 'time',
min: getTodayStart(this.startTime),
max: getStartTime(this.startTime.getTime() + 3600 * 24 * 1000),
splitNumber: 10,
axisLabel: {
margin: 12,
formatter: function (val) {
return new Date(val)
.toLocaleTimeString()
.split(':')
.slice(0, 2)
.join(':');
},
},
axisLine: {
lineStyle: {
color: '#0005',
},
},
boundaryGap: false,
// data: getXaxisRange(getTodayStart(new Date())),
},
]
}
// 构造一个 yAxis
makeYaxis(equipmentName) {
return [
// 主y轴
{
data: equipmentName,
}
]
}
// 构造一个 series
makeSeries(xdata) {
const bgStartTime = this.startTime.getTime();
const bgEndTime = bgStartTime + 3600 * 24 * 1000;
return [
{
type: 'custom',
renderItem: renderItem,
itemStyle: {
opacity: 0.8,
},
encode: {
x: [1, 2],
y: 0,
},
data: xdata,
},
]
}
init(data) {
if (!this.el) throw new Error('没有可供echarts初始化的容器')
if (typeof this.el == 'string') {
this.el = document.querySelector(this.el);
}
this.chart = echarts.init(this.el);
this.handleProps(data);
setTimeout(() => {
// debugger;
this.chart.setOption(this.option);
}, 200);
}
update(data) {
this.clear();
this.init(data);
}
resize() {
this.chart.resize();
}
get option() {
return {
tooltip: this.tooltip,
grid: this.grid,
xAxis: this.xAxis,
yAxis: this.yAxis,
series: this.series,
dataZoom: [
{
type: 'slider',
xAxisIndex: 0,
filterMode: 'weakFilter',
height: 20,
bottom: 0,
start: 0,
end: 80,
handleIcon:
'path://M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
showDetail: false
},
{
type: 'inside',
id: 'insideX',
xAxisIndex: 0,
filterMode: 'weakFilter',
start: 0,
end: 80,
zoomOnMouseWheel: true,
moveOnMouseMove: true
},
{
type: 'slider',
yAxisIndex: 0,
zoomLock: true,
width: 10,
right: 10,
top: 70,
bottom: 20,
start: 0,
end: 100,
handleSize: 0,
showDetail: false
},
{
type: 'inside',
id: 'insideY',
yAxisIndex: 0,
start: 0,
end: 100,
zoomOnMouseWheel: true,
moveOnMouseMove: true,
moveOnMouseWheel: true
}
],
}
}
// 每次 graphList 刷新都会重新渲染整个所有图表
// 可以改进的地方:添加一个 handleAdd() 方法,一次添加一个新的
handleProps(props) {
// props 是父组件的 graphList
console.log('props: ', props);
let ylist = []
let xdata = []
props.forEach((eqArr, index) => {
ylist.push(eqArr.key)
eqArr.forEach(item => {
xdata.push({
name: ['运行', '计划停机', '故障'][item.status],
showName: eqArr.key,
value: [index, item.startTime, item.startTime + item.duration * 60 * 1000, 0],
itemStyle: {
color: types[item.status].color,
}
}
)
})
});
this.grid.push(this.makeGrid());
this.xAxis.push(...this.makeXaxis());
this.yAxis.push(...this.makeYaxis(ylist));
this.series.push(...this.makeSeries(xdata))
}
// handleAdd
handleAdd() { }
clear() {
this.grid = [];
this.xAxis = [];
this.yAxis = [];
this.series = [];
this.chart.dispose();
}
// print option
print() {
console.log(JSON.stringify(this.option, null, 2));
}
}

View File

@@ -0,0 +1,529 @@
<!--
filename: index.vue
author: liubin
date: 2023-09-04 09:34:52
description: 设备状态时序图
-->
<template>
<div class="status-timegraph-container" style="background: #f2f4f9; flex: 1; display: flex; flex-direction: column">
<el-row class="" style="
margin-bottom: 12px;
background: #fff;
padding: 16px 16px 0;
border-radius: 8px;
">
<div class="blue-title">生产节拍时序图</div>
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" :remove-blue="true"
@select-changed="handleSearchBarSelectChange" @headBtnClick="handleSearchBarBtnClick" />
</el-row>
<el-row class="" style="
height: 1px;
flex: 1;
margin-bottom: 12px;
background: #fff;
padding: 16px 16px 32px;
border-radius: 8px;
display: flex;
flex-direction: column;
">
<el-row :gutter="20">
<el-col :span="6">
<div class="blue-title">设备状态时序图</div>
</el-col>
<el-col :span="18" class="legend-row">
<div class="legend">
<div class="icon running"></div>
<div>运行中</div>
</div>
<div class="legend">
<div class="icon fault"></div>
<div>故障</div>
</div>
<div class="legend">
<div class="icon stop"></div>
<div>计划停机</div>
</div>
</el-col>
</el-row>
<div class="main-area" style="flex: 1; display: flex; flex-direction: column;">
<div class="graphs" v-show="graphList.length" id="status-chart" style="height: 1px; flex: 1;"></div>
<h2 v-if="!graphList || graphList.length == 0" class="no-data-bg"></h2>
</div>
</el-row>
<!-- 对话框(添加 / 修改) -->
<base-dialog dialogTitle="添加设备" :dialogVisible="open" width="500px" @close="open = false" @cancel="open = false"
@confirm="submitForm">
<el-select v-if="open" style="width: 100%" v-model="queryParams.equipmentId" placeholder="请选择一个设备">
<el-option v-for="eq in eqList" :key="eq.id" :value="eq.id" :label="eq.name"></el-option>
</el-select>
</base-dialog>
</div>
</template>
<script>
import Gantt from './gantt';
export default {
name: 'SGStatus',
components: {},
props: {},
data() {
return {
chart: null,
searchBarFormConfig: [
{
type: 'select',
label: '产线',
placeholder: '请选择产线',
selectOptions: [],
param: 'lineId',
onchange: true,
},
{
type: 'select',
label: '工段',
placeholder: '请选择工段',
selectOptions: [],
param: 'sectionId',
},
// 时间段
{
type: 'datePicker',
label: '时间段',
dateType: 'date',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
placeholder: '选择日期',
param: 'recordTime',
required: true,
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: 'button',
btnName: '添加对比',
name: 'compare',
color: 'primary',
plain: true,
},
],
queryParams: {
lineId: null,
sectionId: null,
equipmentId: null,
recordTime: null,
},
graphList: [],
existingEquipments: [],
open: false,
eqList: [],
startTime: null,
gantt: null
// demo: [
// [
// {
// equipmentName: '下片机',
// duration: 30,
// relativeDuration: 0.6,
// status: 0,
// startPos: 0,
// startTime: 1691568181000,
// },
// {
// equipmentName: '下片机',
// duration: 20,
// relativeDuration: 0.4,
// status: 2,
// startPos: 30,
// startTime: 1691569981000
// },
// ],
// ],
};
},
computed: {},
created() {
this.initProductline();
this.initWorksection();
this.initEquipment();
// this.getList();
},
mounted() { },
watch: {
graphList: {
handler(val) {
if (val && val.length) {
this.$nextTick(() => {
if (!this.gantt) {
this.gantt = new Gantt('#status-chart', this.startTime);
this.gantt.init(val);
return;
}
this.gantt.update(val);
});
}
return;
},
deep: true,
immediate: true,
},
},
methods: {
findMin() {
let min = 0;
this.graphList.forEach((arr) => {
arr.forEach((item) => {
if (min < item.startTime) min = item.startTime;
});
});
return min;
},
/** 重置查询条件 */
initQuery() {
this.queryParams.lineId = null;
this.queryParams.equipmentId = null;
this.queryParams.sectionId = null;
this.queryParams.recordTime = null;
},
/** 对象到数组的转换 */
objectToArray(obj) {
return Object.keys(obj).map((key) => {
obj[key].sort((a, b) => a.startTime - b.startTime);
obj[key].key = key;
return obj[key];
});
},
async getList() {
const { code, data } = await this.$axios({
url: '/analysis/equipment-analysis/status',
method: 'get',
params: this.queryParams,
});
if (code == 0) {
this.existingEquipments = Object.values(data).map((eq) => eq[0].equipmentId);
this.graphList = this.objectToArray(data);
}
},
/** 准备设备数据 */
async initEquipment() {
const { code, data } = await this.$axios({
url: '/base/equipment/listAll',
method: 'get',
});
if (code == 0) {
this.eqList = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
/** 准备产线数据 */
async initProductline() {
const { code, data } = await this.$axios({
url: '/base/production-line/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[0].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
/** 准备工段数据 */
async initWorksection() {
const { code, data } = await this.$axios({
url: '/base/workshop-section/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
handleSearchBarSelectChange({ param, value }) {
if (!value) {
this.searchBarFormConfig[1].selectOptions = [];
return;
}
switch (param) {
case 'lineId':
this.$axios({
url: '/base/workshop-section/listByParentId',
method: 'get',
params: {
id: value,
},
}).then(({ code, data }) => {
if (code == 0) {
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
});
}
},
handleSearchBarBtnClick({ btnName, ...payload }) {
switch (btnName) {
case 'search':
if (!payload.recordTime || payload.recordTime.length <= 0) {
this.$message.warning('请选择时间段');
return;
}
this.startTime = new Date(payload.recordTime)
this.queryParams.lineId = payload.lineId || null;
this.queryParams.sectionId = payload.sectionId || null;
this.queryParams.equipmentId = payload.equipmentId || null;
this.queryParams.recordTime = payload.recordTime
? [
payload.recordTime,
new Date(
new Date(payload.recordTime).getTime() + 24 * 3600 * 1000
)
.toLocaleDateString()
.split('/')
.map((value, index) => {
if (index == 1 || index == 2) {
return value.padStart(2, '0');
}
return value;
})
.join('-') + ' 00:00:00',
]
: null;
this.getList();
break;
case 'compare':
this.open = true;
break;
}
},
async submitForm() {
if (this.existingEquipments.indexOf(this.queryParams.equipmentId) >= 0) {
this.$message.warning('该设备已存在');
return;
}
const {sectionId,...params} = this.queryParams
const { code, data } = await this.$axios({
url: '/analysis/equipment-analysis/status',
method: 'get',
params: params,
});
if (code == 0) {
const newEqlist = this.objectToArray(data);
if (!newEqlist || newEqlist.length == 0) {
this.$message.warning('该设备没有状态数据');
return;
}
this.graphList.push(newEqlist[0]);
}
this.open = false;
},
},
};
</script>
<style scoped lang="scss">
.graph {
// border: 1px solid #ccc;
// padding: 12px 12px 28px 12px;
// margin: 64px 0;
position: relative;
display: flex;
}
.graph-title {
// position: absolute;
// top: -64px;
// left: -1px;
// padding: 8px 18px;
padding: 0 12px;
font-size: 14px;
line-height: 1;
}
.graph-content {
display: flex;
flex: 1;
padding: 22px 12px;
border: 1px solid #ccc;
border-bottom-width: 2px;
border-top: none;
position: relative;
}
.graph-content::after,
.graph-content::before {
content: '';
position: absolute;
width: 3px;
height: 80%;
background: #fff;
right: -1px;
top: 0;
}
.graph-content::before {
right: unset;
left: -1px;
}
.graph-item,
.graph-item-fixed {
// height: 88px;
// width: 24px;
flex: 1;
// border: 1px solid #ccc;
position: relative;
}
.graph-item-fixed {
flex: unset;
}
.graph-item::before,
.graph-item-fixed::before {
position: absolute;
bottom: -16px;
left: 0;
content: attr(data-time);
// font-size - js
// rotate - js
// color - js, default:
color: #777;
transform-origin: left top;
transform: rotate(12deg);
}
.graph-item-fixed::after,
.graph-item::after {
content: '';
position: absolute;
left: 0;
bottom: -3px;
display: inline-block;
}
.graph-item.tick::after,
.graph-item-fixed.tick::after {
width: 1px;
height: 6px;
border-left: 1px solid #777;
}
.running {
background-color: #288AFF;
// background-color: #84f04e;
}
.waiting {
background-color: #5ad8a6;
// background-color: #409eff;
}
.fault {
// background-color: #ea5b5b;
background-color: #FC9C91;
}
.full {
// background-color: #e6a23c;
background-color: #598fff;
}
.lack {
// background-color: #a69c8d;
background-color: #7585a2;
}
.stop {
background-color: #FFDC94;
}
.legend-row {
margin: 6px 0;
padding-right: 12px;
display: flex;
justify-content: flex-end;
>.legend:not(:last-child) {
margin-right: 12px;
}
.legend {
display: flex;
align-items: center;
}
.icon {
width: 8px;
height: 8px;
border-radius: 2px;
margin-right: 4px;
margin-top: 1px;
}
}
.blue-title {
position: relative;
padding: 4px 0;
padding-left: 12px;
font-size: 14px;
color: #606266;
font-weight: 700;
margin-bottom: 12px;
&::before {
content: '';
position: absolute;
left: 0;
top: 6px;
height: 16px;
width: 4px;
border-radius: 1px;
background: #0b58ff;
}
}
.echarts__status-chart {
background: #ccc;
}
.echarts__status-chart>div {
height: 100% !important;
width: 100% !important;
}
</style>

View File

@@ -6,19 +6,28 @@
--> -->
<template> <template>
<div class="status-timegraph-container" style="background: #f2f4f9; flex: 1; display: flex; flex-direction: column"> <div
<el-row class="" style=" class="status-timegraph-container"
style="background: #f2f4f9; flex: 1; display: flex; flex-direction: column">
<el-row
class=""
style="
margin-bottom: 12px; margin-bottom: 12px;
background: #fff; background: #fff;
padding: 16px 16px 0; padding: 16px 16px 0;
border-radius: 8px; border-radius: 8px;
"> ">
<div class="blue-title">生产节拍时序图</div> <div class="blue-title">生产节拍时序图</div>
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" :remove-blue="true" <SearchBar
@select-changed="handleSearchBarSelectChange" @headBtnClick="handleSearchBarBtnClick" /> :formConfigs="searchBarFormConfig"
ref="search-bar"
:remove-blue="true"
@headBtnClick="handleSearchBarBtnClick" />
</el-row> </el-row>
<el-row class="" style=" <el-row
class=""
style="
height: 1px; height: 1px;
flex: 1; flex: 1;
margin-bottom: 12px; margin-bottom: 12px;
@@ -47,24 +56,43 @@
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<div class="main-area" style="flex: 1; display: flex; flex-direction: column"> <div
<div class="graphs" v-show="graphList.length" id="status-chart" style="height: 1px; flex: 1"></div> class="main-area"
style="flex: 1; display: flex; flex-direction: column">
<div
class="graphs"
v-show="graphList.length"
id="status-chart"
style="height: 1px; flex: 1"></div>
<h2 v-if="!graphList || graphList.length == 0" class="no-data-bg"></h2> <h2 v-if="!graphList || graphList.length == 0" class="no-data-bg"></h2>
</div> </div>
</el-row> </el-row>
<!-- 对话框(添加 / 修改) --> <!-- 对话框(添加 / 修改) -->
<base-dialog dialogTitle="添加设备" :dialogVisible="open" width="500px" @close="open = false" @cancel="open = false" <base-dialog
dialogTitle="添加设备"
:dialogVisible="open"
width="500px"
@close="open = false"
@cancel="open = false"
@confirm="submitForm"> @confirm="submitForm">
<el-select v-if="open" style="width: 100%" v-model="queryParams.equipmentId" placeholder="请选择一个设备"> <el-select
<el-option v-for="eq in eqList" :key="eq.id" :value="eq.id" :label="eq.name"></el-option> v-if="open"
style="width: 100%"
v-model="queryParams.equipmentId"
placeholder="请选择一个设备">
<el-option
v-for="eq in eqList"
:key="eq.id"
:value="eq.id"
:label="eq.name"></el-option>
</el-select> </el-select>
</base-dialog> </base-dialog>
</div> </div>
</template> </template>
<script> <script>
import Gantt from './chart'; import Gantt from './gantt';
export default { export default {
name: 'SGStatus', name: 'SGStatus',
@@ -74,21 +102,6 @@ export default {
return { return {
chart: null, chart: null,
searchBarFormConfig: [ searchBarFormConfig: [
{
type: 'select',
label: '产线',
placeholder: '请选择产线',
selectOptions: [],
param: 'lineId',
onchange: true,
},
{
type: 'select',
label: '工段',
placeholder: '请选择工段',
selectOptions: [],
param: 'sectionId',
},
// 时间段 // 时间段
{ {
type: 'datePicker', type: 'datePicker',
@@ -119,8 +132,6 @@ export default {
}, },
], ],
queryParams: { queryParams: {
lineId: null,
sectionId: null,
equipmentId: null, equipmentId: null,
recordTime: null, recordTime: null,
}, },
@@ -129,37 +140,41 @@ export default {
open: false, open: false,
eqList: [], eqList: [],
startTime: null, startTime: null,
gantt: null gantt: null,
// demo: [
// [
// {
// equipmentName: '下片机',
// duration: 30,
// relativeDuration: 0.6,
// status: 0,
// startPos: 0,
// startTime: 1691568181000,
// },
// {
// equipmentName: '下片机',
// duration: 20,
// relativeDuration: 0.4,
// status: 2,
// startPos: 30,
// startTime: 1691569981000
// },
// ],
// ],
}; };
}, },
computed: {}, computed: {},
created() { created() {
this.initProductline(); const now = new Date();
this.initWorksection(); const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const formattedDate = `${year}-${month}-${day} 00:00:00`;
this.$nextTick(() => {
this.$refs['search-bar'].formInline.recordTime = formattedDate;
});
this.queryParams.equipmentId = Number(this.$route.query.eqid);
this.startTime = new Date(formattedDate);
this.queryParams.recordTime = formattedDate
? [
formattedDate,
new Date(new Date(formattedDate).getTime() + 24 * 3600 * 1000)
.toLocaleDateString()
.split('/')
.map((value, index) => {
if (index == 1 || index == 2) {
return value.padStart(2, '0');
}
return value;
})
.join('-') + ' 00:00:00',
]
: null;
this.getList();
this.initEquipment(); this.initEquipment();
// this.getList();
}, },
mounted() { }, mounted() {
},
watch: { watch: {
graphList: { graphList: {
handler(val) { handler(val) {
@@ -171,7 +186,6 @@ export default {
return; return;
} }
this.gantt.update(val); this.gantt.update(val);
}); });
} }
return; return;
@@ -193,9 +207,7 @@ export default {
/** 重置查询条件 */ /** 重置查询条件 */
initQuery() { initQuery() {
this.queryParams.lineId = null;
this.queryParams.equipmentId = null; this.queryParams.equipmentId = null;
this.queryParams.sectionId = null;
this.queryParams.recordTime = null; this.queryParams.recordTime = null;
}, },
@@ -215,7 +227,9 @@ export default {
params: this.queryParams, params: this.queryParams,
}); });
if (code == 0) { if (code == 0) {
this.existingEquipments = Object.values(data).map((eq) => eq[0].equipmentId); this.existingEquipments = Object.values(data).map(
(eq) => eq[0].equipmentId
);
this.graphList = this.objectToArray(data); this.graphList = this.objectToArray(data);
} }
}, },
@@ -236,65 +250,8 @@ export default {
} }
}, },
/** 准备产线数据 */
async initProductline() {
const { code, data } = await this.$axios({
url: '/base/production-line/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[0].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
/** 准备工段数据 */
async initWorksection() {
const { code, data } = await this.$axios({
url: '/base/workshop-section/listAll',
method: 'get',
});
if (code == 0) {
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
},
handleSearchBarSelectChange({ param, value }) {
if (!value) {
this.searchBarFormConfig[1].selectOptions = [];
return;
}
switch (param) {
case 'lineId':
this.$axios({
url: '/base/workshop-section/listByParentId',
method: 'get',
params: {
id: value,
},
}).then(({ code, data }) => {
if (code == 0) {
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
return {
name: item.name,
id: item.id,
};
});
}
});
}
},
handleSearchBarBtnClick({ btnName, ...payload }) { handleSearchBarBtnClick({ btnName, ...payload }) {
this.queryParams.equipmentId = Number(this.$route.query.eqid);
switch (btnName) { switch (btnName) {
case 'search': case 'search':
if (!payload.recordTime || payload.recordTime.length <= 0) { if (!payload.recordTime || payload.recordTime.length <= 0) {
@@ -302,26 +259,23 @@ export default {
return; return;
} }
this.startTime = new Date(payload.recordTime) this.startTime = new Date(payload.recordTime);
this.queryParams.lineId = payload.lineId || null;
this.queryParams.sectionId = payload.sectionId || null;
this.queryParams.equipmentId = payload.equipmentId || null;
this.queryParams.recordTime = payload.recordTime this.queryParams.recordTime = payload.recordTime
? [ ? [
payload.recordTime, payload.recordTime,
new Date( new Date(
new Date(payload.recordTime).getTime() + 24 * 3600 * 1000 new Date(payload.recordTime).getTime() + 24 * 3600 * 1000
) )
.toLocaleDateString() .toLocaleDateString()
.split('/') .split('/')
.map((value, index) => { .map((value, index) => {
if (index == 1 || index == 2) { if (index == 1 || index == 2) {
return value.padStart(2, '0'); return value.padStart(2, '0');
} }
return value; return value;
}) })
.join('-') + ' 00:00:00', .join('-') + ' 00:00:00',
] ]
: null; : null;
this.getList(); this.getList();
break; break;
@@ -336,10 +290,11 @@ export default {
this.$message.warning('该设备已存在'); this.$message.warning('该设备已存在');
return; return;
} }
const { ...params } = this.queryParams;
const { code, data } = await this.$axios({ const { code, data } = await this.$axios({
url: '/analysis/equipment-analysis/status', url: '/analysis/equipment-analysis/status',
method: 'get', method: 'get',
params: this.queryParams, params: params,
}); });
if (code == 0) { if (code == 0) {
const newEqlist = this.objectToArray(data); const newEqlist = this.objectToArray(data);
@@ -444,7 +399,7 @@ export default {
} }
.running { .running {
background-color: #288AFF; background-color: #288aff;
// background-color: #84f04e; // background-color: #84f04e;
} }
@@ -455,7 +410,7 @@ export default {
.fault { .fault {
// background-color: #ea5b5b; // background-color: #ea5b5b;
background-color: #FC9C91; background-color: #fc9c91;
} }
.full { .full {
@@ -469,7 +424,7 @@ export default {
} }
.stop { .stop {
background-color: #FFDC94; background-color: #ffdc94;
} }
.legend-row { .legend-row {
@@ -478,7 +433,7 @@ export default {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
>.legend:not(:last-child) { > .legend:not(:last-child) {
margin-right: 12px; margin-right: 12px;
} }
@@ -521,7 +476,7 @@ export default {
background: #ccc; background: #ccc;
} }
.echarts__status-chart>div { .echarts__status-chart > div {
height: 100% !important; height: 100% !important;
width: 100% !important; width: 100% !important;
} }

View File

@@ -1,188 +1,182 @@
<template> <template>
<el-form ref="form" :rules="rules" label-width="110px" :model="form"> <el-form ref="form" :rules="rules" label-width="110px" :model="form">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="班次名称" prop="name"> <el-form-item label="工厂" prop="factoryId">
<el-input v-model="form.name"></el-input> <el-select
</el-form-item> v-model="form.factoryId"
</el-col> filterable
<el-col :span="12"> clearable
<el-form-item label="编码" prop="code"> style="width: 100%"
<el-input v-model="form.code" disabled></el-input> placeholder="请选择工厂">
</el-form-item> <el-option
</el-col> v-for="item in factoryArr"
</el-row> :key="item.id"
<el-row> :label="item.name"
<el-col :span="12"> :value="item.id"></el-option>
<el-form-item label="生效时间" prop="enableTime"> </el-select>
<el-date-picker </el-form-item>
v-model="form.enableTime" </el-col>
type="datetime" <el-col :span="12">
placeholder="选择日期时间" <el-form-item label="班次名称" prop="name">
label-format="yyyy-MM-dd HH:mm:ss" <el-input v-model="form.name"></el-input>
value-format="timestamp" </el-form-item>
style="width: 100%;"> </el-col>
</el-date-picker> <el-col :span="12">
</el-form-item> <el-form-item label="编码" prop="code">
</el-col> <el-input v-model="form.code" disabled></el-input>
<el-col :span="12"> </el-form-item>
<el-form-item label="失效时间" prop="disableTime"> </el-col>
<el-date-picker <el-col :span="12">
v-model="form.disableTime" <el-form-item label="班次开始时间" prop="startTime">
type="datetime" <el-time-picker
placeholder="选择日期时间" v-model="form.startTime"
label-format="yyyy-MM-dd HH:mm:ss" format="HH:mm"
value-format="timestamp" value-format="HH:mm"
style="width: 100%;"> style="width: 100%"
</el-date-picker> @change="timeFun('start')"></el-time-picker>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> <el-col :span="12">
<el-row> <el-form-item label="班次结束时间" prop="endTime">
<el-col :span="12"> <el-time-picker
<el-form-item label="班次开始时间" prop="startTime"> v-model="form.endTime"
<el-time-picker format="HH:mm"
v-model="form.startTime" value-format="HH:mm"
format='HH:mm' style="width: 100%"
value-format='HH:mm' @change="timeFun('end')"></el-time-picker>
style="width: 100%;" </el-form-item>
@change="timeFun('start')" </el-col>
> <el-col :span="12">
</el-time-picker> <el-form-item label="是否跨天" prop="daySpan">
</el-form-item> <el-select
</el-col> v-model="form.daySpan"
<el-col :span="12"> placeholder="请选择"
<el-form-item label="班次结束时间" prop="endTime"> disabled
<el-time-picker style="width: 100%">
v-model="form.endTime" <el-option label="否" :value="0"></el-option>
format='HH:mm' <el-option label="是" :value="1"></el-option>
value-format='HH:mm' </el-select>
style="width: 100%;" </el-form-item>
@change="timeFun('end')" </el-col>
> <el-col :span="12">
</el-time-picker> <el-form-item label="备注" prop="remark">
</el-form-item> <el-input v-model="form.remark"></el-input>
</el-col> </el-form-item>
</el-row> </el-col>
<el-row> </el-row>
<el-col :span="12"> </el-form>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否跨天" prop="daySpan">
<el-select v-model="form.daySpan" placeholder="请选择" disabled style="width: 100%;">
<el-option label="否" :value= '0' ></el-option>
<el-option label="是" :value= '1' ></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template> </template>
<script> <script>
import { getGroupClasses, updateGroupClasses, createGroupClasses, getCode } from '@/api/base/groupClasses' import {
getGroupClasses,
updateGroupClasses,
createGroupClasses,
getCode,
} from '@/api/base/groupClasses';
import { getFactoryPage } from '@/api/core/base/factory';
export default { export default {
name: 'groupClassAdd', name: 'groupClassAdd',
data() { data() {
return { return {
form: { form: {
id: '', id: '',
name: '', factoryId: '',
code: '', name: '',
enableTime: '', code: '',
disableTime: '', startTime: '',
startTime: '', endTime: '',
endTime: '', daySpan: '',
daySpan: '', remark: '',
remark: '' },
}, isEdit: false, //是否是编辑
isEdit: false, //是否是编辑 factoryArr: [],
rules: { rules: {
name: [{ required: true, message: '请输入班组名称', trigger: 'blur' }], factoryId: [
enableTime: [{ required: true, message: '请选择班次开始时间', trigger: 'change' }], { required: true, message: '请选择工厂', trigger: 'change' },
code: [{ required: true, message: '请输入编码', trigger: 'blur' }], ],
startTime: [{ required: true, message: '请输入生效时间', trigger: 'change' }], name: [{ required: true, message: '请输入班组名称', trigger: 'blur' }],
endTime: [{ required: true, message: '请选择班次结束时间', trigger: 'change' }] code: [{ required: true, message: '请输入编码', trigger: 'blur' }],
} startTime: [
} { required: true, message: '请选择班次开始时间', trigger: 'change' },
}, ],
methods: { endTime: [
init(id) { { required: true, message: '请选择班次结束时间', trigger: 'change' },
if (id) { ],
this.isEdit = true },
this.form.id = id };
getGroupClasses(id).then((res) => { },
if (res.code === 0) { created() {
this.form = res.data const params = {
} pageSize: 100,
}) pageNo: 1,
} else { };
this.isEdit = false getFactoryPage(params).then((res) => {
this.form.id = '' this.factoryArr = res.data.list || [];
getCode().then((res) => { });
this.form.code = res.data },
}) methods: {
} init(id) {
}, if (id) {
timeFun(val) { this.isEdit = true;
if (this.form.startTime && this.form.endTime) { this.form.id = id;
if (this.form.startTime > this.form.endTime) { getGroupClasses(id).then((res) => {
this.form.daySpan = 1 if (res.code === 0) {
} else if (this.form.startTime < this.form.endTime) { this.form = res.data;
this.form.daySpan = 0 }
} else { });
if (val === 'start') { } else {
this.form.startTime = '' this.isEdit = false;
} else { this.form.id = '';
this.form.endTime = '' getCode().then((res) => {
} this.form.code = res.data;
this.$modal.msgWarning('班次开始时间和结束时间不能相同') });
} }
} },
}, timeFun(val) {
submitForm() { if (this.form.startTime && this.form.endTime) {
this.$refs['form'].validate((valid) => { if (this.form.startTime > this.form.endTime) {
if (valid) { this.form.daySpan = 1;
let obj = {} } else if (this.form.startTime < this.form.endTime) {
if (this.form.disableTime) { this.form.daySpan = 0;
obj = this.form } else {
} else { if (val === 'start') {
obj.id = this.form.id this.form.startTime = '';
obj.name = this.form.name } else {
obj.code = this.form.code this.form.endTime = '';
obj.enableTime = this.form.enableTime }
obj.startTime = this.form.startTime this.$modal.msgWarning('班次开始时间和结束时间不能相同');
obj.endTime = this.form.endTime }
obj.daySpan = this.form.daySpan }
obj.remark = this.form.remark },
} submitForm() {
if (this.isEdit) { this.$refs['form'].validate((valid) => {
//编辑 if (valid) {
updateGroupClasses({ ...obj }).then((res) => { if (this.isEdit) {
if (res.code === 0) { //编辑
this.$modal.msgSuccess("操作成功"); updateGroupClasses({ ...this.form }).then((res) => {
this.$emit('successSubmit') if (res.code === 0) {
} this.$modal.msgSuccess('操作成功');
}) this.$emit('successSubmit');
} else { }
createGroupClasses({ ...obj }).then((res) => { });
if (res.code === 0) { } else {
this.$modal.msgSuccess("操作成功"); createGroupClasses({ ...this.form }).then((res) => {
this.$emit('successSubmit') if (res.code === 0) {
} this.$modal.msgSuccess('操作成功');
}) this.$emit('successSubmit');
} }
} else { });
return false }
} } else {
}) return false;
}, }
formClear() { });
this.$refs.form.resetFields() },
this.isEdit = false formClear() {
} this.$refs.form.resetFields();
} this.isEdit = false;
} },
},
};
</script> </script>

View File

@@ -0,0 +1,53 @@
<!--
* @Author: zwq
* @Date: 2024-07-01 14:53:55
* @LastEditors: zwq
* @LastEditTime: 2025-01-14 13:09:33
* @Description:
-->
<template>
<el-switch v-model="state" type="text" size="small" :disabled="readonly" @change="changeHandler" />
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({})
}
},
data() {
return {
state: false
}
},
computed: {
readonly() {
return !!this.injectData.readonly
}
},
mounted() {
this.mapToState()
},
methods: {
mapToState() {
if (this.injectData.prop === 'enabled') {
this.state = this.injectData.enabled === 1 ? true : false
}
},
changeHandler() {
let params = {}
let payload = {}
params.name = 'state'
payload.id = this.injectData.id
payload.enabled = this.state ? '1' : '0'
payload.startTime = this.injectData.startTime
payload.endTime = this.injectData.endTime
payload.factoryId = this.injectData.factoryId
params.payload = payload
this.$emit('emitData', params)
}
}
}
</script>

View File

@@ -1,260 +1,293 @@
<!--
* @Author: zwq
* @Date: 2024-07-01 14:53:55
* @LastEditors: zwq
* @LastEditTime: 2025-02-24 16:02:39
* @Description:
-->
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 --> <search-bar
<search-bar :formConfigs="formConfig"
:formConfigs="formConfig" ref="searchBarForm"
ref="searchBarForm" @headBtnClick="buttonClick" />
@headBtnClick="buttonClick" <!-- 列表 -->
/> <base-table
<!-- 列表 --> :page="queryParams.pageNo"
<base-table :limit="queryParams.pageSize"
:page="queryParams.pageNo" :table-props="tableProps"
:limit="queryParams.pageSize" :table-data="list"
:table-props="tableProps" :max-height="tableH"
:table-data="list" @emitFun="handleTableEvents">
:max-height="tableH" <method-btn
> v-if="tableBtn.length"
<method-btn slot="handleBtn"
v-if="tableBtn.length" :width="120"
slot="handleBtn" label="操作"
:width="120" :method-list="tableBtn"
label="操作" @clickBtn="handleClick" />
:method-list="tableBtn" </base-table>
@clickBtn="handleClick" <pagination
/> :page.sync="queryParams.pageNo"
</base-table> :limit.sync="queryParams.pageSize"
<pagination :total="total"
:page.sync="queryParams.pageNo" @pagination="getList" />
:limit.sync="queryParams.pageSize" <!-- 新增 -->
:total="total" <base-dialog
@pagination="getList" :dialogTitle="addOrEditTitle"
/> :dialogVisible="centervisible"
<!-- 新增 --> @cancel="handleCancel"
<base-dialog @confirm="handleConfirm"
:dialogTitle="addOrEditTitle" :before-close="handleCancel"
:dialogVisible="centervisible" width="50%">
@cancel="handleCancel" <group-class-add ref="classList" @successSubmit="successSubmit" />
@confirm="handleConfirm" </base-dialog>
:before-close="handleCancel" </div>
width='50%'
>
<group-class-add ref="classList" @successSubmit="successSubmit" />
</base-dialog>
</div>
</template> </template>
<script> <script>
import { getGroupClassesPage, deleteGroupClasses, updateGroupClasses } from "@/api/base/groupClasses"; import {
import GroupClassAdd from './components/groupClassAdd.vue' getGroupClassesPage,
import { formatDate } from '@/utils' deleteGroupClasses,
updateGroupClasses,
} from '@/api/base/groupClasses';
import GroupClassAdd from './components/groupClassAdd.vue';
import StatusBtn from './components/statusBtn';
import tableHeightMixin from '@/mixins/tableHeightMixin';
import { getFactoryPage } from '@/api/core/base/factory';
const tableProps = [ const tableProps = [
{ {
prop: 'enableTimeStr', prop: 'factoryName',
label: '生效时段', label: '工厂',
minWidth: 300 },
}, {
{ prop: 'name',
prop: 'name', label: '班次名称',
label: '班次名称' },
}, {
{ prop: 'timeStr',
prop: 'timeStr', label: '班次时间',
label: '班次时间', minWidth: 100,
minWidth: 100 },
}, {
{ prop: 'code',
prop: 'code', label: '班次编码',
label: '班次编码', minWidth: 200,
minWidth: 200 },
}, {
{ prop: 'enabled',
prop: 'status', label: '班次状态',
label: '班次状态' subcomponent: StatusBtn,
}, },
{ // {
prop: 'remark', // prop: 'remark',
label: '备注' // label: '备注',
} // },
] ];
export default { export default {
name: "GroupClass", name: 'GroupClass',
components: { GroupClassAdd }, components: { GroupClassAdd },
data() { mixins: [tableHeightMixin],
return { data() {
formConfig: [ return {
{ formConfig: [
type: 'input', {
label: '班次名称', type: 'select',
placeholder: '班次名称', label: '工厂',
param: 'name' selectOptions: [],
}, param: 'factoryId',
{ onchange: true,
type: 'button', },
btnName: '查询', {
name: 'search', type: 'input',
color: 'primary' label: '班次名称',
}, placeholder: '班次名称',
{ param: 'name',
type: 'separate' },
}, {
{ type: 'button',
type: this.$auth.hasPermi('base:group-classes:create') ? 'button' : '', btnName: '查询',
btnName: '新增', name: 'search',
name: 'add', color: 'primary',
color: 'success', },
plain: true {
} type: 'separate',
], },
tableProps, {
tableBtn: [ type: this.$auth.hasPermi('base:group-classes:create')
{ ? 'button'
type: 'cancel', : '',
btnName: '作废', btnName: '新增',
showParam: { name: 'add',
type: '&', color: 'success',
data: [ plain: true,
{ },
type: 'unequal', ],
name: 'status', tableProps,
value: '不可用' tableBtn: [
} this.$auth.hasPermi('base:group-classes:update')
] ? {
} type: 'edit',
}, btnName: '编辑',
this.$auth.hasPermi('base:group-classes:update') }
? { : undefined,
type: 'edit', this.$auth.hasPermi('base:group-classes:delete')
btnName: '编辑' ? {
} type: 'delete',
: undefined, btnName: '删除',
this.$auth.hasPermi('base:group-classes:delete') }
? { : undefined,
type: 'delete', ].filter((v) => v),
btnName: '删除' // 总条数
} total: 0,
: undefined // 班次基础信息列表
].filter((v) => v), list: [],
tableH: this.tableHeight(260), // 弹出层标题
// 总条数 addOrEditTitle: '',
total: 0, // 是否显示弹出层
// 班次基础信息列表 centervisible: false,
list: [], // 查询参数
// 弹出层标题 queryParams: {
addOrEditTitle: "", pageNo: 1,
// 是否显示弹出层 pageSize: 20,
centervisible: false, name: null,
// 查询参数 },
queryParams: { };
pageNo: 1, },
pageSize: 20, created() {
name: null this.getList();
} this.getPdLineList();
}; },
}, methods: {
created() { getPdLineList() {
window.addEventListener('resize', () => { const params = {
this.tableH = this.tableHeight(260) pageSize: 100,
}) pageNo: 1,
this.getList() };
}, getFactoryPage(params).then((res) => {
methods: { this.formConfig[0].selectOptions = res.data.list || [];
buttonClick(val) { });
switch (val.btnName) { },
case 'search': buttonClick(val) {
this.queryParams.pageNo = 1; switch (val.btnName) {
this.queryParams.name = val.name case 'search':
this.getList() this.queryParams.pageNo = 1;
break this.queryParams.name = val.name;
default: this.queryParams.factoryId = val.factoryId || undefined;
this.addOrEditTitle = '新增' this.getList();
this.centervisible = true break;
this.$nextTick(() => { default:
this.$refs.classList.init() this.addOrEditTitle = '新增';
}) this.centervisible = true;
} this.$nextTick(() => {
}, this.$refs.classList.init();
/** 查询列表 */ });
getList() { }
getGroupClassesPage(this.queryParams).then(res => { },
if (res.code === 0 && res.data.list.length > 0) { // 班组状态
res.data.list.map(item => { handleTableEvents(params) {
item.enableTimeStr = formatDate(item.enableTime) + '至' + (item.disableTime ? formatDate(item.disableTime) : '永久') if (params.name === 'state') {
item.timeStr = item.startTime.slice(0, 5) + '-' + item.endTime.slice(0, 5) // 班组状态
item.status = item.status === true ? '可用' : '不可用' updateGroupClasses({ ...params.payload })
}) .then((res) => {
this.list = res.data.list; if (res.code === 0) {
this.total = res.data.total; this.$modal.msgSuccess('操作成功');
} else { this.getList();
this.list = [] }
this.total = 0 })
} .catch((res) => {
}); this.getList();
}, });
handleClick(val) { }
switch (val.type) { },
case 'edit': /** 查询列表 */
this.addOrEditTitle = '编辑' getList() {
this.$nextTick(() => { getGroupClassesPage(this.queryParams).then((res) => {
this.$refs.classList.init(val.data.id) if (res.code === 0 && res.data.list && res.data.list.length > 0) {
}) res.data.list.map((item) => {
this.centervisible = true item.timeStr =
break item.startTime.slice(0, 5) + '-' + item.endTime.slice(0, 5);
case 'cancel': });
this.discard(val.data) this.list = res.data.list;
break this.total = res.data.total;
default: } else {
this.handleDelete(val.data) this.list = [];
} this.total = 0;
}, }
handleCancel() { });
this.$refs.classList.formClear() },
this.centervisible = false handleClick(val) {
this.addOrEditTitle = '' switch (val.type) {
}, case 'edit':
handleConfirm() { this.addOrEditTitle = '编辑';
this.$refs.classList.submitForm() this.$nextTick(() => {
}, this.$refs.classList.init(val.data.id);
successSubmit() { });
this.handleCancel() this.centervisible = true;
this.getList() break;
}, default:
discard(row) { this.handleDelete(val.data);
let obj = {} }
obj.id = row.id },
obj.startTime = row.startTime handleCancel() {
obj.endTime = row.endTime this.$refs.classList.formClear();
obj.enableTime = row.enableTime this.centervisible = false;
obj.disableTime = Date.parse(new Date()) this.addOrEditTitle = '';
this.$modal.confirm('是否确认作废班次名称为"' + row.name + '"的数据项?').then(function() { },
return updateGroupClasses({ ...obj }) handleConfirm() {
}).then(() => { this.$refs.classList.submitForm();
this.getList(); },
this.$modal.msgSuccess("操作成功"); successSubmit() {
}).catch(() => {}); this.handleCancel();
}, this.getList();
/** 删除按钮操作 */ },
handleDelete(row) { /** 删除按钮操作 */
console.log(row) handleDelete(row) {
let _this = this let _this = this;
if (row.status === '可用') {// 可用 if (row.enabled) {
_this.$modal.confirm('删除的班次"' + row.name + '"可能会影响交接班计划,请点取消再次确认!').then(function() { // 可用
return _this.$modal.confirm('是否确认删除班次名称为"' + row.name + '"的数据项?').then(function() { this.$confirm(
return deleteGroupClasses(row.id); `是否确认删除 ${row.name} 的数据项?`,
}).then(() => { '可能会影响交接班计划!',
_this.getList(); {
_this.$modal.msgSuccess("删除成功"); confirmButtonText: '确定',
}).catch(() => {}); cancelButtonText: '取消',
}) type: 'warning',
} else { }
_this.$modal.confirm('是否确认删除班次名称为"' + row.name + '"的数据项?').then(function() { ).then(function () {
return deleteGroupClasses(row.id); return _this
}).then(() => { .$confirm(`是否确认删除 ${row.name} 的数据项?`, '系统提示', {
_this.getList(); confirmButtonText: '确定',
_this.$modal.msgSuccess("删除成功"); cancelButtonText: '取消',
}).catch(() => {}); type: 'warning',
} })
} .then(function () {
} return deleteGroupClasses(row.id);
})
.then(() => {
_this.getList();
_this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
});
} else {
this.$confirm(`是否确认删除 ${row.name} 的数据项?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(function () {
return deleteGroupClasses(row.id);
})
.then(() => {
_this.getList();
_this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
}
},
},
}; };
</script> </script>

View File

@@ -0,0 +1,278 @@
<template>
<div class="baseTable">
<el-table
:ref="id"
:data="renderData"
v-bind="$attrs"
:border="cancelBorder ? false : true"
@current-change="currentChange"
@selection-change="handleSelectionChange"
style="width: 100%"
:header-cell-style="{
background: '#F2F4F9',
color: '#606266',
}">
<!-- 多选 -->
<el-table-column
v-if="selectWidth"
type="selection"
:width="selectWidth" />
<!-- 序号 -->
<el-table-column
v-if="page && limit"
prop="_pageIndex"
:width="pageWidth"
align="center"
:fixed="cancelPageFixed ? false : true">
<template slot="header">
<el-popover placement="bottom-start" width="300" trigger="click">
<div
class="setting-box"
style="max-height: 400px; overflow-y: auto">
<el-checkbox
v-for="(item, index) in tableProps"
:key="'cb' + index"
v-model="selectedBox[index]"
:label="item.label" />
</div>
<i slot="reference" class="el-icon-s-tools" />
</el-popover>
</template>
</el-table-column>
<el-table-column
v-for="item in renderTableHeadList"
:key="item.prop"
v-bind="item"
:label="item.label"
:prop="item.prop"
:fixed="item.fixed || false"
:show-overflow-tooltip="item.showOverflowtooltip || false"
:sortable="item.sortable || false">
<template slot="header">
<span>{{ item.label }}</span>
</template>
<!-- 多表头 -->
<template v-if="item.children">
<el-table-column
v-for="sub in item.children"
:prop="sub.prop"
:key="sub.prop"
v-bind="sub"
:label="sub.label">
<template v-if="sub.children">
<el-table-column
v-for="ssub in sub.children"
:prop="ssub.prop"
:key="ssub.prop"
v-bind="ssub"
:label="ssub.label">
<template slot-scope="sscopeInner">
<component
:is="ssub.subcomponent"
v-if="ssub.subcomponent"
:key="sscopeInner.row.id"
:inject-data="{ ...sscopeInner.row, ...ssub }"
@emitData="emitData" />
<span v-else>
{{ sscopeInner.row[ssub.prop] | commonFilter(ssub.filter) }}
</span>
</template>
</el-table-column>
</template>
<template slot-scope="scopeInner">
<component
:is="sub.subcomponent"
v-if="sub.subcomponent"
:key="scopeInner.row.id"
:inject-data="{ ...scopeInner.row, ...sub }"
@emitData="emitData" />
<span v-else>
{{ scopeInner.row[sub.prop] | commonFilter(sub.filter) }}
</span>
</template>
</el-table-column>
</template>
<template slot-scope="scope">
<component
:is="item.subcomponent"
v-if="item.subcomponent"
:key="scope.row.id"
:itemProp="item.prop"
:inject-data="{ ...scope.row, ...item }"
@emitData="emitData" />
<span v-else>
{{ scope.row[item.prop] | commonFilter(item.filter) }}
</span>
</template>
</el-table-column>
<slot name="handleBtn" />
</el-table>
<!-- 表格底部加号 -->
<el-button
v-if="addButtonShow"
class="addButton"
icon="el-icon-plus"
@click="emitButtonClick">
{{ addButtonShow }}
</el-button>
</div>
</template>
<script>
export default {
name: 'BaseTable',
filters: {
commonFilter: (source, filterType = (a) => a) => {
return filterType(source);
},
},
props: {
cancelBorder: {
type: Boolean,
default: false,
},
cancelPageFixed: {
type: Boolean,
default: false,
},
tableData: {
type: Array,
required: true,
default: () => {
return [];
},
},
tableProps: {
type: Array,
default: () => {
return [];
},
},
id: {
type: String,
required: false,
default: '',
},
page: {
type: Number,
required: false,
default: 0,
},
pageWidth: {
type: Number,
required: false,
default: 70,
},
limit: {
type: Number,
required: false,
default: 0,
},
selectWidth: {
type: Number,
required: false,
default: 0,
},
addButtonShow: {
type: String,
required: false,
default: '',
},
},
data() {
return {
selectedBox: new Array(100).fill(true),
};
},
computed: {
renderTableHeadList() {
return this.tableProps.filter((item, index) => {
return this.selectedBox[index];
});
},
renderData() {
return this.tableData.map((item, index) => {
return {
...item,
_pageIndex: (this.page - 1) * this.limit + index + 1,
};
});
},
},
beforeMount() {
this.selectedBox = new Array(100).fill(true);
},
methods: {
currentChange(newVal, oldVal) {
this.$emit('current-change', { newVal, oldVal });
},
handleSelectionChange(val) {
this.$emit('selection-change', val);
},
emitData(val) {
this.$emit('emitFun', val);
},
emitButtonClick() {
this.$emit('emitButtonClick');
},
setCurrent(name, index) {
let _this = this;
let obj = _this.$refs[name].data[index];
_this.$refs[name].setCurrentRow(obj);
},
doLayout(name) {
this.$refs[name].doLayout();
},
},
};
</script>
<style scoped>
.baseTable .show-col-btn {
margin-right: 5px;
line-height: inherit;
cursor: pointer;
}
.baseTable .el-icon-refresh {
cursor: pointer;
}
.baseTable >>> .el-table .el-table__cell {
padding: 0;
height: 35px;
border: 1px solid rgb(220, 220, 220);
}
</style>
<style>
.baseTable .el-table__body tr.current-row > td.el-table__cell {
background-color: #eaf1fc;
}
.baseTable .el-table .el-table__cell {
padding: 0;
height: 35px;
}
.baseTable .addButton {
width: 100%;
height: 35px;
border-top: none;
color: #0b58ff;
border-color: #ebeef5;
border-radius: 0;
}
.baseTable .addButton:hover {
color: #0b58ff;
border-color: #ebeef5;
background-color: #fff;
}
.baseTable .addButton:focus {
border-color: #ebeef5;
background-color: #fff;
}
.el-tooltip__popper.is-dark {
background: rgba(0, 0, 0, 0.6) !important;
}
.el-tooltip__popper .popper__arrow,
.el-tooltip__popper .popper__arrow::after {
border-top-color: rgba(0, 0, 0, 0.4) !important;
}
</style>

View File

@@ -0,0 +1,331 @@
<!--
* @Author: zwq
* @Date: 2023-08-24 14:47:58
* @LastEditors: zwq
* @LastEditTime: 2025-02-25 14:03:40
* @Description:
-->
<template>
<div>
<search-bar :formConfigs="formConfig" ref="searchBarForm" @headBtnClick="buttonClick" />
<el-table id="detail" :data="tableData" :header-cell-style="{
background: '#F2F4F9',
color: '#606266',
}" border v-loading="dataListLoading" style="width: 100%" ref="dataList">
<el-table-column prop="lineName" label="产线" align="center" />
<!-- <el-table-column prop="sizes" width="105" showOverflowtooltip align="center" label="规格" /> -->
<!-- <el-table-column prop="process" label="产品工艺" align="center" /> -->
<el-table-column prop="inputN" label="磨边" align="center">
<el-table-column prop="edgeNum" label="投入数量/片" />
<el-table-column prop="edgeTime" label="数据上报时间">
<template v-slot="scope">
<span>
{{
scope.row.reportType === 0
? parseTime(scope.row.edgeTime)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="outputN" label="打孔/丝印" align="center">
<el-table-column prop="drillCoating" label="投入数量">
<template v-slot="scope">
<span>
{{
(scope.row.drillNum ?? '-')
+ '/'
+ (scope.row.coatingNum ?? '-')
}}
</span>
</template>
</el-table-column>
<el-table-column prop="coatingTime" label="数据上报时间">
<template v-slot="scope">
<span>
{{
scope.row.reportType === 0
? parseTime(scope.row.coatingTime)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="lossN" label="镀膜" align="center">
<el-table-column prop="silkNum" label="投入数量" />
<el-table-column prop="silkTime" label="数据上报时间">
<template v-slot="scope">
<span>
{{
scope.row.reportType === 0
? parseTime(scope.row.silkTime)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="lossN" label="钢化" align="center">
<el-table-column prop="temperingNum" label="投入数量" />
<el-table-column prop="temperingTime" label="数据上报时间">
<template v-slot="scope">
<span>
{{
scope.row.reportType === 0
? parseTime(scope.row.temperingTime)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="lossN" label="包装" align="center">
<el-table-column prop="packingNum" label="投入数量" />
<el-table-column prop="packingTime" label="数据上报时间">
<template v-slot="scope">
<span>
{{
scope.row.reportType === 0
? parseTime(scope.row.packingTime)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<!-- <el-table-column prop="lossRatio" label="不良率/%">
<template v-slot="scope">
<span>
{{
scope.row.lossRatio != null ? scope.row.lossRatio.toFixed(2) : '-'
}}
</span>
</template>
</el-table-column>
<el-table-column prop="outputRatio" label="投入产出率/%">
<template v-slot="scope">
<span>
{{
scope.row.outputRatio != null
? scope.row.outputRatio.toFixed(2)
: '-'
}}
</span>
</template>
</el-table-column>
<el-table-column prop="processingRatio" label="加工成品率/%">
<template v-slot="scope">
<span>
{{
scope.row.processingRatio != null
? scope.row.processingRatio.toFixed(2)
: '-'
}}
</span>
</template>
</el-table-column>
<el-table-column prop="lossD" label="不良详情" align="center">
<el-table-column prop="original" label="原片" align="center">
<el-table-column prop="originalLossNum" label="原片不良/片" />
<el-table-column prop="originalLossArea" label="原片不良/m²">
<template v-slot="scope">
<span>
{{
scope.row.originalLossArea != null
? scope.row.originalLossArea.toFixed(2)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="edge" label="磨边" align="center">
<el-table-column prop="edgeLossNum" label="磨边不良/片" />
<el-table-column prop="edgeLossArea" label="磨边不良/m²">
<template v-slot="scope">
<span>
{{
scope.row.edgeLossArea != null
? scope.row.edgeLossArea.toFixed(2)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="drill" label="打孔" align="center">
<el-table-column prop="drillLossNum" label="打孔不良/片" />
<el-table-column prop="drillLossArea" label="打孔不良/m²">
<template v-slot="scope">
<span>
{{
scope.row.drillLossArea != null
? scope.row.drillLossArea.toFixed(2)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="coating" label="镀膜" align="center">
<el-table-column prop="coatingLossNum" label="镀膜不良/片" />
<el-table-column prop="coatingLossArea" label="镀膜不良/m²">
<template v-slot="scope">
<span>
{{
scope.row.coatingLossArea != null
? scope.row.coatingLossArea.toFixed(2)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="silk" label="丝印" align="center">
<el-table-column prop="silkLossNum" label="丝印不良/片" />
<el-table-column prop="silkLossArea" label="丝印不良/m²">
<template v-slot="scope">
<span>
{{
scope.row.silkLossArea != null
? scope.row.silkLossArea.toFixed(2)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column prop="tempering" label="钢化" align="center">
<el-table-column prop="temperingLossNum" label="钢化不良/片" />
<el-table-column prop="temperingLossArea" label="钢化不良/m²">
<template v-slot="scope">
<span>
{{
scope.row.temperingLossArea != null
? scope.row.temperingLossArea.toFixed(2)
: '-'
}}
</span>
</template>
</el-table-column>
</el-table-column> -->
<el-table-column prop="down" label="下片" align="center">
<el-table-column prop="downNum" label="成品数量" />
<el-table-column prop="scrapNum" label="废片数量" />
<el-table-column prop="inputOutputRate" label="投入产出率" />
<el-table-column prop="yieldRate" label="加工成品率" />
</el-table-column>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { getTeamReportPageDet, exportGroupProductReportExcel } from '@/api/core/monitoring/auto';
import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';
export default {
components: {},
data() {
return {
tableData: [],
id:null,
dataListLoading: false,
formConfig: [
{
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
},
],
};
},
components: {},
created() {},
mounted() {},
methods: {
// 获取数据列表
init(id) {
this.id = id
this.dataListLoading = true;
getTeamReportPageDet(id).then((response) => {
this.tableData = response.data?.map((item, index) => {
item.originalLossNum = item.original?.lossNum;
item.originalLossArea = item.original?.lossArea;
item.edgeLossNum = item.edge?.lossNum;
item.edgeLossArea = item.edge?.lossArea;
item.drillLossNum = item.drill?.lossNum;
item.drillLossArea = item.drill?.lossArea;
item.coatingLossNum = item.coating?.lossNum;
item.coatingLossArea = item.coating?.lossArea;
item.silkLossNum = item.silk?.lossNum;
item.silkLossArea = item.silk?.lossArea;
item.temperingLossNum = item.tempering?.lossNum;
item.temperingLossArea = item.tempering?.lossArea;
item.packingLossNum = item.packing?.lossNum;
item.packingLossArea = item.packing?.lossArea;
if (item.isSummaryReport) {
item.lineName = '合计';
}
return item;
});
this.dataListLoading = false;
});
},
// arraySpanMethod({ row, column, rowIndex, columnIndex }) {
// if (row.isSummaryReport) {
// if (columnIndex === 0) {
// return [1, 3];
// } else if (columnIndex === 1) {
// return [0, 0];
// } else if (columnIndex === 2) {
// return [0, 0];
// }
// }
// },
buttonClick(val) {
switch (val.btnName) {
case 'export':
this.handleExport();
break;
default:
console.log(val);
}
},
handleExport() {
this.$modal.confirm('是否确认导出').then(() => {
return exportGroupProductReportExcel({id:this.id});
}).then(response => {
console.log(response)
this.$download.excel(response, '班组生产报表-详情.xls');
}).catch(() => {})
// let tables = document.querySelector('#detail').cloneNode(true);
// 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',
// }),
// '班组生产报表-详情.xlsx'
// );
// } catch (e) {
// if (typeof console !== 'undefined') console.log(e, exportTableOut);
// }
// return exportTableOut;
},
},
};
</script>

View File

@@ -0,0 +1,594 @@
<!--
* @Author: Do not edit
* @Date: 2023-08-29 14:59:29
* @LastEditTime: 2025-02-25 14:26:04
* @LastEditors: zwq
* @Description:
-->
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<base-table-s
v-if="showData.length"
class="right-aside"
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="showData">
<method-btn
v-if="showData.length"
slot="handleBtn"
:width="80"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table-s>
<div v-else class="no-data-bg"></div>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="addOrUpdateVisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
close-on-click-modal
top="0"
width="80%">
<gr-detail ref="grDetail" />
<slot name="footer">
<el-row slot="footer" type="flex" justify="end">
<el-col :span="24">
<el-button size="small" class="btnTextStyle" @click="handleCancel">
取消
</el-button>
</el-col>
</el-row>
</slot>
</base-dialog>
</div>
</template>
<script>
import grDetail from './gr-detail';
import { getTeamReportPage } from '@/api/core/monitoring/auto';
import { getFactoryPage } from '@/api/core/base/factory';
import { getGroupTeamPage } from '@/api/base/groupTeam';
// import codeFilter from '../../mixins/code-filter'
import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';
import baseTableS from './baseTable.vue';
import { parseTime } from '@/filter/code-filter';
const tableProps = [
{
prop: 'reportType',
label: '报表类型',
fixed: true
},
{
prop: 'reportDate',
label: '日期',
width: 180,
fixed: true
},
{
prop: 'factoryName',
label: '工厂',
fixed: true
},
{
prop: 'teamName',
label: '班组',
fixed: true
},
{
prop: 'edgeNum',
label: '磨边',
fixed: true
}, {
prop: 'drillOrCoating',
label: '打孔/丝印',
fixed: true
}, {
prop: 'silkNum',
label: '镀膜',
fixed: true
}, {
prop: 'temperingNum',
label: '钢化',
fixed: true
}, {
prop: 'packingNum',
label: '包装',
fixed: true
},
{
prop: 'inputN',
label: '下片',
align: 'center',
children: [
{
prop: 'downNum',
label: '成品数量',
width:100
},
{
prop: 'scrapNum',
label: '废片数量',
width:100
},
{
prop: 'inputOutputRate',
label: '投入产出率',
width: 100
},
{
prop: 'yieldRate',
label: '加工成品率',
width: 100
},
],
},
// {
// prop: 'outputN',
// label: '产出',
// align: 'center',
// children: [
// {
// prop: 'outputNum',
// label: '产出数量/片',
// width:100
// },
// {
// prop: 'outputArea',
// label: '产出面积/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// {
// prop: 'lossN',
// label: '不良',
// align: 'center',
// children: [
// {
// prop: 'lossNum',
// label: '不良数量/片',
// width:100
// },
// {
// prop: 'lossArea',
// label: '不良面积/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// {
// prop: 'lossRatio',
// label: '不良率/%',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// {
// prop: 'outputRatio',
// label: '投入产出率/%',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:110
// },
// {
// prop: 'processingRatio',
// label: '加工成品率/%',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:110
// },
// {
// prop: 'lossD',
// label: '不良详情',
// align: 'center',
// children: [
// {
// prop: 'original',
// label: '原片',
// align: 'center',
// children: [
// {
// prop: 'originalLossNum',
// label: '原片不良/片',
// width:100
// },
// {
// prop: 'originalLossArea',
// label: '原片不良/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// {
// prop: 'edge',
// label: '磨边',
// align: 'center',
// children: [
// {
// prop: 'edgeLossNum',
// label: '磨边不良/片',
// width:100
// },
// {
// prop: 'edgeLossArea',
// label: '磨边不良/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// {
// prop: 'drill',
// label: '打孔',
// align: 'center',
// children: [
// {
// prop: 'drillLossNum',
// label: '打孔不良/片',
// width:100
// },
// {
// prop: 'drillLossArea',
// label: '打孔不良/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// {
// prop: 'coating',
// label: '镀膜',
// align: 'center',
// children: [
// {
// prop: 'coatingLossNum',
// label: '镀膜不良/片',
// width:100
// },
// {
// prop: 'coatingLossArea',
// label: '镀膜不良/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// {
// prop: 'silk',
// label: '丝印',
// align: 'center',
// children: [
// {
// prop: 'silkLossNum',
// label: '丝印不良/片',
// width:100
// },
// {
// prop: 'silkLossArea',
// label: '丝印不良/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// {
// prop: 'tempering',
// label: '钢化',
// align: 'center',
// children: [
// {
// prop: 'temperingLossNum',
// label: '钢化不良/片',
// width:100
// },
// {
// prop: 'temperingLossArea',
// label: '钢化不良/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// {
// prop: 'packing',
// label: '包装',
// align: 'center',
// children: [
// {
// prop: 'packingLossNum',
// label: '包装不良/片',
// width:100
// },
// {
// prop: 'packingLossArea',
// label: '包装不良/㎡',
// filter: (val) => (val != null ? val.toFixed(2) : '-'),
// width:100
// },
// ],
// },
// ],
// },
];
export default {
components: {
baseTableS,
grDetail,
},
data() {
return {
urlOptions: {
getDataListURL: getTeamReportPage,
},
listQuery: {
reportType: 1,
pageSize: 10,
pageNo: 1,
startTime: undefined,
endTime: undefined,
total: 1,
},
fileName: '',
dataListLoading: false,
tableProps,
tableBtn: [
this.$auth.hasPermi(`monitoring:group-off:update`)
? {
type: 'eq',
btnName: '详情',
}
: undefined,
].filter((v) => v),
showData: [],
tableData: [],
formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
},
{
type: 'select',
label: '班组',
selectOptions: [],
param: 'teamId',
},
{
type: 'select',
label: '报表类型',
selectOptions: [
{
id: 0,
name: '班',
},
{
id: 1,
name: '日',
},
// {
// id: 2,
// name: '周',
// },
{
id: 3,
name: '月',
},
{
id: 4,
name: '年',
},
],
defaultSelect: 1,
param: 'reportType',
},
{
type: 'datePicker',
label: '时间范围',
dateType: 'daterange',
format: 'yyyy-MM-dd',
valueFormat: 'timestamp',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'timeVal',
},
{
type: this.$auth.hasPermi('monitoring:group-off:query') ? 'button' : '',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('monitoring:group-off:export') ? 'button' : '',
// type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
},
],
addOrEditTitle: '',
addOrUpdateVisible: false,
};
},
created() {
// 获取当前时间
const now = new Date();
// 获取前一天的同一时间
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
// 设置为00:00:00
yesterday.setHours(0, 0, 0, 0);
// 设置为23:59:59
const end = new Date(yesterday.getTime());
end.setHours(23, 59, 59, 59);
this.listQuery.startTime = yesterday.getTime(), [end.getTime()];
this.listQuery.endTime = end.getTime()
this.$nextTick(() => {
this.$refs.searchBarForm.formInline.timeVal = [yesterday.getTime(),end.getTime()];
});
this.getDataList();
this.getPdLineList();
},
methods: {
handleExport() {
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);
exportTable.Sheets.Sheet1.A1.v = '序号' //导出表格第一列表头为序号
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;
},
getPdLineList() {
const params = {
pageSize: 100,
pageNo: 1,
};
getGroupTeamPage(params).then((res) => {
this.formConfig[1].selectOptions = res.data.list || [];
});
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.factoryId = val.factoryId || undefined;
this.listQuery.teamId = val.teamId || undefined;
this.listQuery.reportType = val.reportType || undefined;
this.listQuery.startTime = val.timeVal
? val.timeVal[0]
: undefined;
this.listQuery.endTime = val.timeVal
? val.timeVal[1]
: undefined;
this.getDataList();
break;
case 'export':
this.handleExport();
break;
default:
console.log(val);
}
},
// 获取数据列表
getDataList() {
this.dataListLoading = true;
console.log(this.listQuery);
const arr = ['班', '日', '', '月', '年']; // 索引0对应班1对应日3对应月4对应年索引2留空
this.urlOptions.getDataListURL(this.listQuery).then((response) => {
if (!response.data.list) {
this.showData = [];
this.dataListLoading = false;
return;
}
this.tableData = response.data?.list.map((item, index) => {
item.reportType = arr[item.reportType] || item.reportType;
item.drillOrCoating = item.drillNum + "/" + item.coatingNum
item.originalLossNum = item.original?.lossNum;
item.originalLossArea = item.original?.lossArea;
item.edgeLossNum = item.edge?.lossNum;
item.edgeLossArea = item.edge?.lossArea;
item.drillLossNum = item.drill?.lossNum;
item.drillLossArea = item.drill?.lossArea;
item.coatingLossNum = item.coating?.lossNum;
item.coatingLossArea = item.coating?.lossArea;
item.silkLossNum = item.silk?.lossNum;
item.silkLossArea = item.silk?.lossArea;
item.temperingLossNum = item.tempering?.lossNum;
item.temperingLossArea = item.tempering?.lossArea;
item.packingLossNum = item.packing?.lossNum;
item.packingLossArea = item.packing?.lossArea;
return item;
});
this.listQuery.total = response.data?.total;
this.dataListLoading = false;
this.showData = this.tableData;
});
},
handleClick(val) {
this.addOrUpdateVisible = true;
const time = val.data.timeVal ? parseTime(val.data.timeVal[0]) + '-' + parseTime(val.data.timeVal[1]) : '- '
const teamName = val.data.teamName?val.data.teamName:'- '
const teamLeader = val.data.teamLeader?val.data.teamLeader:'- '
this.addOrEditTitle =
'时间:' +
time +
' 班组:' +
teamName +
' 组长:' +
teamLeader +
' 详情';
this.$nextTick(() => {
this.$refs.grDetail.init(val.data.id);
});
},
handleCancel() {
this.addOrUpdateVisible = false;
this.addOrEditTitle = '';
},
handleConfirm() {
this.handleCancel();
},
// 每页数
sizeChangeHandle(val) {
this.listQuery.pageSize = val;
this.listQuery.pageNo = 1;
this.getDataList();
},
// 当前页
currentChangeHandle(val) {
this.listQuery.pageNo = val;
this.getDataList();
},
},
};
</script>

View File

@@ -1,96 +1,144 @@
<template> <template>
<el-form ref="form" :rules="rules" label-width="80px" :model="form"> <el-form ref="form" :rules="rules" label-width="100px" :model="form">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="班组名称" prop="name"> <el-form-item label="工厂" prop="factoryId">
<el-input v-model="form.name"></el-input> <el-select
</el-form-item> v-model="form.factoryId"
</el-col> filterable
<el-col :span="12"> clearable
<el-form-item label="班组编码" prop="code"> style="width: 100%"
<el-input v-model="form.code" disabled></el-input> placeholder="请选择工厂">
</el-form-item> <el-option
</el-col> v-for="item in factoryArr"
</el-row> :key="item.id"
<el-row> :label="item.name"
<el-col :span="12"> :value="item.id"></el-option>
<el-form-item label="班组人数" prop="num"> </el-select>
<el-input-number v-model="form.num" :min="1" :max="99999999" style="width: 100%;"></el-input-number> </el-form-item>
</el-form-item> </el-col>
</el-col> <el-col :span="12">
<el-col :span="12"> <el-form-item label="班组名称" prop="name">
<el-form-item label="班组组长" prop="leaderName"> <el-input v-model="form.name"></el-input>
<el-input v-model="form.leaderName"></el-input> </el-form-item>
</el-form-item> </el-col>
</el-col> <el-col :span="12">
</el-row> <el-form-item label="班组编码" prop="code">
</el-form> <el-input v-model="form.code" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班组组长" prop="leaderName">
<el-input v-model="form.leaderName" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号" prop="leaderPhone">
<el-input v-model="form.leaderPhone" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班组人数" prop="num">
<el-input-number
style="width: 100%"
v-model="form.num"
:step="1"
step-strictly></el-input-number>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template> </template>
<script> <script>
import { getGroupTeam, updateGroupTeam, createGroupTeam, getCode } from '@/api/base/groupTeam' import {
getGroupTeam,
updateGroupTeam,
createGroupTeam,
getCode,
} from '@/api/base/groupTeam';
import { getFactoryPage } from '@/api/core/base/factory';
export default { export default {
name: 'groupTeamAdd', name: 'groupTeamAdd',
data() { data() {
return { return {
form: { form: {
id: '', id: '',
name: '', factoryId: '',
code: '', name: '',
num: null, code: '',
leaderName: '' leaderName: '',
}, leaderPhone: '',
isEdit: false, //是否是编辑 num: '',
rules: { },
name: [{ required: true, message: '请输入班组名称', trigger: 'blur' }] factoryArr: [], //工厂
} isEdit: false, //是否是编辑
} rules: {
}, factoryId: [
methods: { { required: true, message: '请选择工厂', trigger: 'change' },
init(id) { ],
if (id) { name: [{ required: true, message: '请输入班组名称', trigger: 'blur' }],
this.isEdit = true code: [{ required: true, message: '请输入班组编码', trigger: 'blur' }],
this.form.id = id leaderName: [
getGroupTeam( id ).then((res) => { { required: true, message: '请输入组长', trigger: 'blur' },
if (res.code === 0) { ],
this.form = res.data },
} };
}) },
} else { created() {
this.isEdit = false const params = {
this.form.id = '' pageSize: 100,
getCode().then((res) => { pageNo: 1,
this.form.code = res.data };
}) getFactoryPage(params).then((res) => {
} this.factoryArr = res.data.list || [];
}, });
submitForm() { },
this.$refs['form'].validate((valid) => { methods: {
if (valid) { init(id) {
if (this.isEdit) { if (id) {
//编辑 this.isEdit = true;
updateGroupTeam({ ...this.form }).then((res) => { this.form.id = id;
if (res.code === 0) { getGroupTeam(id).then((res) => {
this.$modal.msgSuccess("操作成功"); if (res.code === 0) {
this.$emit('successSubmit') this.form = res.data;
} }
}) });
} else { } else {
createGroupTeam({ ...this.form }).then((res) => { this.isEdit = false;
if (res.code === 0) { this.form.id = '';
this.$modal.msgSuccess("操作成功"); getCode().then((res) => {
this.$emit('successSubmit') this.form.code = res.data;
} });
}) }
} },
} else { submitForm() {
return false this.$refs['form'].validate((valid) => {
} if (valid) {
}) if (this.isEdit) {
}, //编辑
formClear() { updateGroupTeam({ ...this.form }).then((res) => {
this.$refs.form.resetFields() if (res.code === 0) {
this.isEdit = false this.$modal.msgSuccess('操作成功');
} this.$emit('successSubmit');
} }
} });
} else {
createGroupTeam({ ...this.form }).then((res) => {
if (res.code === 0) {
this.$modal.msgSuccess('操作成功');
this.$emit('successSubmit');
}
});
}
} else {
return false;
}
});
},
formClear() {
this.$refs.form.resetFields();
this.isEdit = false;
},
},
};
</script> </script>

View File

@@ -1,3 +1,10 @@
<!--
* @Author: zwq
* @Date: 2024-07-01 14:53:55
* @LastEditors: zwq
* @LastEditTime: 2024-07-10 10:00:03
* @Description:
-->
<template> <template>
<el-switch v-model="state" type="text" size="small" :disabled="readonly" @change="changeHandler" /> <el-switch v-model="state" type="text" size="small" :disabled="readonly" @change="changeHandler" />
</template> </template>
@@ -12,8 +19,7 @@ export default {
}, },
data() { data() {
return { return {
state: false, state: false
payload: {}
} }
}, },
computed: { computed: {
@@ -31,9 +37,17 @@ export default {
} }
}, },
changeHandler() { changeHandler() {
this.payload.id = this.injectData.id let params = {}
this.payload.enabled = this.state ? '1' : '0' let payload = {}
this.$emit('emitData', this.payload) params.name = 'state'
payload.id = this.injectData.id
payload.enabled = this.state ? '1' : '0'
payload.code = this.injectData.code
payload.name = this.injectData.name
payload.factoryId = this.injectData.factoryId
payload.leaderName = this.injectData.leaderName
params.payload = payload
this.$emit('emitData', params)
} }
} }
} }

View File

@@ -0,0 +1,305 @@
<template>
<div>
<el-drawer :title="title" :visible.sync="visible" size="70%" @close='closeD' :show-close='false'>
<div class="box">
<el-row class="topBox">
<el-col :span="6">
<p class="boldTitle">班组名称</p>
<p class="lightText">{{ teamData.teamName }}</p>
</el-col>
<el-col :span="6">
<p class="boldTitle">班组长</p>
<p class="lightText">{{ teamData.leaderName }}</p>
</el-col>
<el-col :span="6">
<p class="boldTitle">班组人数</p>
<p class="lightText">{{ teamData.teamNum }}</p>
</el-col>
<el-col :span="6">
<p class="boldTitle">手机号</p>
<p class="lightText">{{ teamData.leaderTelephone }}</p>
</el-col>
</el-row>
<div class="bottomBox">
<!-- 搜索工作栏 -->
<search-bar
v-if="visible"
:formConfigs="formConfig"
@headBtnClick="buttonClick"
/>
<base-table
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-props="tableProps"
:table-data="tableData"
>
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="100"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick"
/>
</base-table>
<pagination
:page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize"
:total="total"
@pagination="getList"
/>
</div>
</div>
</el-drawer>
<!-- 新增编辑组员 -->
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="centervisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width='40%'
>
<worker-team-add ref="workerTeamAdd" @successSubmit="successSubmit" />
</base-dialog>
</div>
</template>
<script>
const tableProps = [
{
prop: 'workerName',
label: '人员姓名'
},
{
prop: 'workerMajorName',
label: '专业'
},
{
prop: 'workerTelephone',
label: '手机'
},
{
prop: 'remark',
label: '备注'
}
]
import { groupTeamPage, teamDetDelete } from '@/api/base/groupTeam'
import { getWorker } from '@/api/base/worker'
import WorkerTeamAdd from './workerTeamAdd.vue'
export default {
name: 'WorkerEdit',
data() {
return {
visible: false,
title: '',
formConfig: [],
teamData: {
teamName: '',
leaderName: '',
teamNum: '',
leaderTelephone: '-',
teamId: ''
},
queryParams: {
pageNo: 1,
pageSize: 20,
teamId: '',
workerName: ''
},
tableProps,
tableData: [],
tableBtn: [],
total: 0,
// 弹出层标题
addOrEditTitle: "",
// 是否显示弹出层
centervisible: false
}
},
components: { WorkerTeamAdd },
created() {
},
methods: {
init(val) {
this.visible = true
this.teamData.teamName = val.payload.name
this.teamData.leaderName = val.payload.leaderName
this.teamData.teamNum = val.payload.num
this.teamData.teamId = val.payload.teamId
this.queryParams.teamId = val.payload.id
getWorker({id:val.payload.leaderId}).then(res => {// 获取组长手机号
this.teamData.leaderTelephone = res.data.telephone || '-'
})
this.getList()
if (val.name === 'view') {
this.title = '查看组员'
this.tableBtn = []
this.formConfig = [
{
type: 'input',
label: '关键字',
placeholder: '姓名',
param: 'workerName'
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary'
}
]
}else{
this.title = '编辑组员'
this.tableBtn = [
{
type: 'edit',
btnName: '编辑'
},
{
type: 'delete',
btnName: '删除'
}
]
this.formConfig = [
{
type: 'input',
label: '关键字',
placeholder: '姓名',
param: 'workerName'
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary'
},
{
type: 'separate'
},
{
type: 'button',
btnName: '新增',
name: 'add',
color: 'success',
plain: true
}
]
}
},
getList() {
groupTeamPage({ ...this.queryParams }).then(res => {
if (res.code === 0 && res.data.list && res.data.list.length > 0) {
let arr = []
res.data.list.map(item => {
let obj = {}
obj.workerName = item.worker.name
obj.workerMajorName = item.worker.majorName
obj.workerTelephone = item.worker.telephone
obj.remark = item.remark
obj.id = item.id
arr.push(obj)
})
this.tableData = arr
this.total = res.data.total
} else {
this.tableData = []
this.total = 0
}
})
},
buttonClick(val) {
console.log(val)
if (val.btnName === 'search') {
this.queryParams.workerName = val.workerName
this.queryParams.pageNo = 1
this.getList()
}else if (val.btnName === 'add') {
this.addNew()
}
},
// 新增
addNew() {
this.addOrEditTitle = '新增'
this.centervisible = true
this.$nextTick(() => {
this.$refs.workerTeamAdd.init({'teamId': this.queryParams.teamId, id: ''})
})
},
handleCancel() {
this.$refs.workerTeamAdd.formClear()
this.centervisible = false
this.addOrEditTitle = ''
},
handleConfirm() {
this.$refs.workerTeamAdd.submitForm()
},
successSubmit() {
this.handleCancel()
this.getList()
},
handleClick(val) {
console.log(val)
switch (val.type) {
case 'edit':
this.addOrEditTitle = '编辑'
this.centervisible = true
this.$nextTick(() => {
this.$refs.workerTeamAdd.init({'teamId': this.queryParams.teamId, 'id': val.data.id, 'workName':val.data.workerName, 'majorName':val.data.workerMajorName})
})
break
default:
this.handleDelete(val.data)
}
},
/** 删除按钮操作 */
handleDelete(row) {
console.log(row)
this.$modal.confirm('是否确认删除人员"' + row.workerName + '"的数据项?').then(function() {
return teamDetDelete({id: row.id});
}).then(() => {
this.queryParams.pageNo = 1;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
closeD() {
this.teamData.teamName = ''
this.teamData.leaderName = ''
this.teamData.teamNum = ''
this.teamData.leaderTelephone = ''
this.teamData.teamId = ''
this.queryParams.pageNo = 1
this.queryParams.pageSize = 20
this.queryParams.teamId = ''
this.queryParams.workerName = ''
this.total = 0
this.$emit('closeDrawer')
}
}
}
</script>
<style lang='scss' scoped>
.box {
padding:0 30px;
.topBox {
padding-bottom: 30px;
border-bottom: 1px solid #E9E9E9;
.boldTitle {
font-size: 14px;
font-weight: 600;
color: rgba(0,0,0,0.85);
margin: 0;
margin-bottom: 10px;
}
.lightText {
font-size: 14px;
font-weight: 400;
color: rgba(102,102,102,0.75);
margin: 0;
}
}
.bottomBox {
padding-top: 30px;
}
}
</style>

View File

@@ -0,0 +1,41 @@
<template>
<div class="workerOperate">
<div class="operateBtn">
<span class="view" v-if="this.$auth.hasPermi('base:group-team:view-worker')" @click="emitParams('view')">查看</span>
<span class="edit" v-if="this.$auth.hasPermi('base:group-team:edit-worker')" @click="emitParams('edit')">编辑</span>
</div>
</div>
</template>
<script>
export default {
name: 'WorkerOperate',
props: {
injectData: {
type: Object,
default: () => ({})
}
},
methods: {
emitParams(data) {
let params = {}
params.name = data
params.payload = this.injectData
this.$emit('emitData', params)
}
}
}
</script>
<style lang='scss' scoped>
.workerOperate {
.operateBtn{
color: #0B58FF;
.view {
margin-right: 10px;
cursor: pointer;
}
.edit {
cursor: pointer;
}
}
}
</style>

View File

@@ -0,0 +1,121 @@
<template>
<el-form ref="form" :rules="rules" label-width="100px" :model="form">
<el-form-item label="员工" prop="workerId" v-if='!isEdit'>
<el-select v-model="form.workerId" placeholder="请选择" filterable style="width: 100%;" @change="selectWorker()">
<el-option
v-for="item in workerList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="员工" prop="workerId" v-if='isEdit'>
<el-input v-model="workName" disabled></el-input>
</el-form-item>
<el-form-item label="专业" prop="majorName">
<el-input v-model="form.majorName" disabled></el-input>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark"></el-input>
</el-form-item>
</el-form>
</template>
<script>
import { otherWorkerList } from '@/api/base/worker'
import { teamDetCreate, teamDetUpdate, groupTeamDet } from '@/api/base/groupTeam'
export default {
name: 'WorkerTeamAdd',
data() {
return {
workerList: [],
form: {
teamId: '',
workerId: '',
remark: '',
majorName: '',
id: ''
},
isEdit: false,
workName: '',//编辑时用
rules: {
workerId: [{ required: true, message: '员工不能为空', trigger: 'change' }]
}
}
},
methods: {
init(param) {
this.form.teamId = param.teamId
this.form.majorName = param.majorName
this.workName = param.workName
otherWorkerList({teamId:this.form.teamId}).then(res => {
this.workerList = res.data || []
if (param.id) {
this.isEdit = true
this.form.id = param.id
groupTeamDet({id: this.form.id}).then((res) => {
if (res.code === 0) {
this.form.workerId = res.data.workerId
this.form.remark = res.data.remark
}
})
} else {
this.isEdit = false
this.form.id = ''
}
})
},
selectWorker() {
if (this.form.workerId) {
this.workerList.map(item => {
if (item.id === this.form.workerId) {
this.form.majorName = item.majorName
}
})
}else{
this.form.majorName = ''
}
},
// 确定
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.isEdit) {
// 编辑
teamDetUpdate({
teamId: this.form.teamId,
workerId: this.form.workerId,
remark: this.form.remark,
id: this.form.id
}).then((res) => {
if (res.code === 0) {
this.$modal.msgSuccess("操作成功");
this.$emit('successSubmit')
}
})
} else {
teamDetCreate({
teamId: this.form.teamId,
workerId: this.form.workerId,
remark: this.form.remark
}).then((res) => {
if (res.code === 0) {
this.$modal.msgSuccess("操作成功");
this.$emit('successSubmit')
}
})
}
} else {
return false
}
})
},
formClear() {
this.$refs.form.resetFields()
this.workName = ''
this.form.majorName = ''
this.isEdit = false
}
}
}
</script>

View File

@@ -1,225 +1,264 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 --> <search-bar
<search-bar :formConfigs="formConfig"
:formConfigs="formConfig" ref="searchBarForm"
ref="searchBarForm" @headBtnClick="buttonClick" />
@headBtnClick="buttonClick" <!-- 列表 -->
/> <base-table
<!-- 列表 --> :page="queryParams.pageNo"
<base-table :limit="queryParams.pageSize"
:page="queryParams.pageNo" :table-props="tableProps"
:limit="queryParams.pageSize" :table-data="list"
:table-props="tableProps" :max-height="tableH"
:table-data="list" @emitFun="handleTableEvents">
:max-height="tableH" <method-btn
@emitFun="handleTableEvents" v-if="tableBtn.length"
> slot="handleBtn"
<method-btn :width="80"
v-if="tableBtn.length" label="操作"
slot="handleBtn" :method-list="tableBtn"
:width="80" @clickBtn="handleClick" />
label="操作" </base-table>
:method-list="tableBtn" <pagination
@clickBtn="handleClick" :page.sync="queryParams.pageNo"
/> :limit.sync="queryParams.pageSize"
</base-table> :total="total"
<pagination @pagination="getList" />
:page.sync="queryParams.pageNo" <!-- 新增 -->
:limit.sync="queryParams.pageSize" <base-dialog
:total="total" :dialogTitle="addOrEditTitle"
@pagination="getList" :dialogVisible="centervisible"
/> @cancel="handleCancel"
<!-- 新增 --> @confirm="handleConfirm"
<base-dialog :before-close="handleCancel"
:dialogTitle="addOrEditTitle" width="40%">
:dialogVisible="centervisible" <group-team-add ref="groupList" @successSubmit="successSubmit" />
@cancel="handleCancel" </base-dialog>
@confirm="handleConfirm" </div>
:before-close="handleCancel"
>
<group-team-add ref="groupList" @successSubmit="successSubmit" />
</base-dialog>
</div>
</template> </template>
<script> <script>
import { getGroupTeamPage, deleteGroupTeam, updateGroupTeam } from "@/api/base/groupTeam"; import {
import { parseTime } from '@/utils/ruoyi' getGroupTeamPage,
import GroupTeamAdd from './components/groupTeamAdd.vue' deleteGroupTeam,
import StatusBtn from './components/statusBtn.vue' updateGroupTeam,
} from '@/api/base/groupTeam';
import { parseTime } from '@/utils/ruoyi';
import GroupTeamAdd from './components/groupTeamAdd';
import StatusBtn from './components/statusBtn';
import tableHeightMixin from '@/mixins/tableHeightMixin';
import { getFactoryPage } from '@/api/core/base/factory';
const tableProps = [ const tableProps = [
{ {
prop: 'createTime', prop: 'createTime',
label: '创建时间', label: '创建时间',
filter: parseTime, filter: parseTime,
minWidth: 150 minWidth: 160,
}, },
{ {
prop: 'name', prop: 'factoryName',
label: '班组名称' label: '工厂',
}, },
{ {
prop: 'code', prop: 'name',
label: '班组编码', label: '班组名称',
minWidth: 220 },
}, {
{ prop: 'code',
prop: 'num', label: '编码',
label: '班组人数' minWidth: 220,
}, },
{ {
prop: 'leaderName', prop: 'num',
label: '班组组长' label: '班组人数',
}, },
{ {
prop: 'enabled', prop: 'leaderName',
label: '班组状态', label: '组长',
subcomponent: StatusBtn },
} {
] prop: 'enabled',
label: '班组状态',
subcomponent: StatusBtn,
},
];
export default { export default {
name: "GroupTeam", name: 'GroupTeam',
components: { GroupTeamAdd }, components: { GroupTeamAdd },
data() { mixins: [tableHeightMixin],
return { data() {
formConfig: [ return {
{ formConfig: [
type: 'input', {
label: '班组名称', type: 'select',
placeholder: '班组名称', label: '工厂',
param: 'name' selectOptions: [],
}, param: 'factoryId',
{ onchange: true,
type: 'input', },
label: '班组编码', {
placeholder: '班组编码', type: 'input',
param: 'code' label: '班组名称',
}, placeholder: '班组名称',
{ param: 'name',
type: 'button', },
btnName: '查询', {
name: 'search', type: 'input',
color: 'primary' label: '组长',
}, placeholder: '组长',
{ param: 'leaderName',
type: 'separate' },
}, {
{ type: 'button',
type: this.$auth.hasPermi('base:group-team:create') ? 'button' : '', btnName: '查询',
btnName: '新增', name: 'search',
name: 'add', color: 'primary',
color: 'success', },
plain: true {
} type: 'separate',
], },
tableProps, {
tableBtn: [ type: this.$auth.hasPermi('base:group-team:create') ? 'button' : '',
this.$auth.hasPermi('base:group-team:update') btnName: '新增',
? { name: 'add',
type: 'edit', color: 'success',
btnName: '编辑' plain: true,
} },
: undefined, ],
this.$auth.hasPermi('base:group-team:delete') tableProps,
? { tableBtn: [
type: 'delete', this.$auth.hasPermi('base:group-team:update')
btnName: '删除' ? {
} type: 'edit',
: undefined btnName: '编辑',
].filter((v) => v), }
tableH: this.tableHeight(260), : undefined,
// 总条数 this.$auth.hasPermi('base:group-team:delete')
total: 0, ? {
// 班次基础信息列表 type: 'delete',
list: [], btnName: '删除',
// 弹出层标题 }
addOrEditTitle: "", : undefined,
// 是否显示弹出层 ].filter((v) => v),
centervisible: false, // 总条数
// 查询参数 total: 0,
queryParams: { // 班次基础信息列表
pageNo: 1, list: [],
pageSize: 20, // 弹出层标题
name: null, addOrEditTitle: '',
code: null // 是否显示弹出层
} centervisible: false,
}; // 查询参数
}, queryParams: {
created() { pageNo: 1,
window.addEventListener('resize', () => { pageSize: 20,
this.tableH = this.tableHeight(260) name: null,
}) code: null,
this.getList(); },
}, };
methods: { },
buttonClick(val) { created() {
switch (val.btnName) { this.getList();
case 'search': this.getPdLineList();
this.queryParams.pageNo = 1; },
this.queryParams.name = val.name methods: {
this.queryParams.code = val.code getPdLineList() {
this.getList() const params = {
break pageSize: 100,
default: pageNo: 1,
this.addOrEditTitle = '新增' };
this.centervisible = true getFactoryPage(params).then((res) => {
this.$nextTick(() => { this.formConfig[0].selectOptions = res.data.list || [];
this.$refs.groupList.init() });
}) },
} buttonClick(val) {
}, switch (val.btnName) {
/** 查询列表 */ case 'search':
getList() { this.queryParams.pageNo = 1;
getGroupTeamPage(this.queryParams).then(response => { this.queryParams.leaderName = val.leaderName;
this.list = response.data.list; this.queryParams.factoryId = val.factoryId || undefined;
this.total = response.data.total; this.queryParams.name = val.name;
}); this.getList();
}, break;
handleClick(val) { default:
switch (val.type) { this.addOrEditTitle = '新增';
case 'edit': this.centervisible = true;
this.addOrEditTitle = '编辑' this.$nextTick(() => {
this.$nextTick(() => { this.$refs.groupList.init();
this.$refs.groupList.init(val.data.id) });
}) }
this.centervisible = true },
break /** 查询列表 */
default: getList() {
this.handleDelete(val.data) getGroupTeamPage(this.queryParams).then((response) => {
} this.list = response.data.list;
}, this.total = response.data.total;
// 班组状态 });
handleTableEvents(data) { },
updateGroupTeam({ ...data }).then((res) => { handleClick(val) {
if (res.code === 0) { switch (val.type) {
this.$modal.msgSuccess("操作成功"); case 'edit':
} this.addOrEditTitle = '编辑';
this.$nextTick(() => {
this.$refs.groupList.init(val.data.id);
});
this.centervisible = true;
break;
default:
this.handleDelete(val.data);
}
},
// 班组状态
handleTableEvents(params) {
if (params.name === 'state') {
// 班组状态
updateGroupTeam({ ...params.payload })
.then((res) => {
if (res.code === 0) {
this.$modal.msgSuccess('操作成功');
this.getList();
}
})
.catch((res) => {
this.getList();
});
}
},
handleCancel() {
this.$refs.groupList.formClear();
this.centervisible = false;
this.addOrEditTitle = '';
},
handleConfirm() {
this.$refs.groupList.submitForm();
},
successSubmit() {
this.handleCancel();
this.getList();
},
/** 删除按钮操作 */
handleDelete(row) {
this.$confirm(`是否确认删除 ${row.name} 的数据项?`, "系统提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}) })
}, .then(function () {
handleCancel() { return deleteGroupTeam(row.id);
this.$refs.groupList.formClear() })
this.centervisible = false .then(() => {
this.addOrEditTitle = '' this.queryParams.pageNo = 1;
}, this.getList();
handleConfirm() { this.$modal.msgSuccess('删除成功');
this.$refs.groupList.submitForm() })
}, .catch(() => {});
successSubmit() { },
this.handleCancel() closeDrawer() {
this.getList() this.getList();
}, },
/** 删除按钮操作 */ },
handleDelete(row) {
this.$modal.confirm('是否确认删除班组名称为"' + row.name + '"的数据项?').then(function() {
return deleteGroupTeam(row.id);
}).then(() => {
this.queryParams.pageNo = 1;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
}
}; };
</script> </script>

View File

@@ -95,7 +95,8 @@ export default {
type: this.$auth.hasPermi('base:group-team:create') ? 'button' : '', type: this.$auth.hasPermi('base:group-team:create') ? 'button' : '',
btnName: '导出', btnName: '导出',
name: 'export', name: 'export',
color: 'warning', color: 'success',
plain: true
} }
], ],
tableProps, tableProps,
@@ -143,4 +144,4 @@ export default {
.box { .box {
padding: 0 32px; padding: 0 32px;
} }
</style> </style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,213 @@
<!--
* @Author: zwq
* @Date: 2025-01-15 11:20:41
* @LastEditors: zwq
* @LastEditTime: 2025-02-25 09:37:50
* @Description:
-->
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<!-- 列表 -->
<base-table
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-props="tableProps"
:table-data="list"
:max-height="tableH">
</base-table>
<pagination
:page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize"
:total="total"
@pagination="getList" />
</div>
</template>
<script>
import { parseTime } from '@/utils/ruoyi';
import tableHeightMixin from '@/mixins/tableHeightMixin';
import { schedulingPage,exportSchedulingExcel } from '@/api/base/groupTeamScheduling';
import { getFactoryPage } from '@/api/core/base/factory';
import {
getGroupClassesPage,
} from '@/api/base/groupClasses';
import {
getGroupTeamPage,
} from '@/api/base/groupTeam';
import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';
const tableProps = [
{
prop: 'factoryName',
label: '工厂',
},
{
prop: 'startDay',
label: '上班日期',
filter: (val) => (val ? parseTime(val, '{y}-{m}-{d}') : '-'),
},
{
prop: 'startTime',
label: '上班时间',
filter: (val) => (val ? parseTime(val, '{h}:{i}') : '-'),
width: 100,
},
{
prop: 'endTime',
label: '下班时间',
filter: (val) => (val ? parseTime(val, '{h}:{i}') : '-'),
width: 100,
},
{
prop: 'classesName',
label: '班次名称',
},
{
prop: 'teamName',
label: '班组名称',
},
];
export default {
mixins: [tableHeightMixin],
data() {
return {
formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'select',
label: '班次',
selectOptions: [],
param: 'classesId',
},
{
type: 'select',
label: '班组',
selectOptions: [],
param: 'teamId',
},
{
type: 'datePicker',
label: '上班日期',
dateType: 'daterange',
format: 'yyyy-MM-dd',
valueFormat: 'yyyy-MM-dd HH:mm:ss',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'timeVal',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
type: 'button',
btnName: '导出',
name: 'export',
color: 'warning',
},
],
tableProps,
// 总条数
total: 0,
// 班次基础信息列表
list: [],
// 弹出层标题
addOrEditTitle: '',
// 是否显示弹出层
centervisible: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 20,
},
};
},
created() {
this.getList();
this.getPdLineList();
},
methods: {
/** 导出按钮操作 */
handleExport() {
// 处理查询参数
let params = { ...this.queryParams };
params.pageNo = undefined;
params.pageSize = undefined;
this.$modal.confirm('是否确认导出所有数据项?').then(() => {
this.exportLoading = true;
return exportSchedulingExcel(params);
}).then(response => {
this.$download.excel(response, '上班记录报表.xls');
this.exportLoading = false;
}).catch(() => { });
},
getPdLineList() {
const params = {
pageSize: 100,
pageNo: 1,
};
getGroupClassesPage(params).then((res) => {
this.formConfig[1].selectOptions = res.data.list || [];
});
getGroupTeamPage(params).then((res) => {
this.formConfig[2].selectOptions = res.data.list || [];
});
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.queryParams.pageNo = 1;
this.queryParams.factoryId = val.factoryId || undefined;
this.queryParams.classesId = val.classesId || undefined;
this.queryParams.teamName = val.teamId || undefined;
this.queryParams.startDay = val.timeVal
? val.timeVal
: undefined;
this.getList();
break;
case 'export':
this.queryParams.pageNo = 1;
this.queryParams.factoryId = val.factoryId || undefined;
this.queryParams.classesId = val.classesId || undefined;
this.queryParams.teamName = val.teamId || undefined;
this.queryParams.startDay = val.timeVal
? val.timeVal
: undefined;
this.handleExport();
break;
default:
console.log(val);
}
},
/** 查询列表 */
getList() {
schedulingPage(this.queryParams).then((response) => {
this.list = response.data.list;
this.total = response.data.total;
});
},
},
};
</script>

View File

@@ -0,0 +1,240 @@
<!--
* @Author: zwq
* @Date: 2024-07-10 13:43:41
* @LastEditors: zwq
* @LastEditTime: 2025-01-14 11:06:24
* @Description:
-->
<template>
<el-form ref="form" :rules="rules" label-width="110px" :model="form">
<el-row>
<el-col :span="12">
<el-form-item label="工厂" prop="factoryId">
<el-select
v-model="form.factoryId"
filterable
clearable
style="width: 100%"
placeholder="请选择工厂">
<el-option
v-for="item in factoryArr"
:key="item.id"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="计划名称" prop="name">
<el-input v-model="form.name" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="相关班组" prop="teamIdList">
<el-select
v-model="form.teamIdList"
filterable
clearable
multiple
style="width: 100%"
placeholder="请选择班组">
<el-option
v-for="item in teamList"
:key="item.id"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="相关班次" prop="classesIdList">
<el-select
v-model="form.classesIdList"
filterable
clearable
multiple
style="width: 100%"
placeholder="请选择班次">
<el-option
v-for="item in classList"
:key="item.id"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" v-if="false">
<el-form-item label="是否生产班组" prop="isProduction">
<el-radio-group v-model="form.isProduction">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24" v-show="form.isProduction">
<tree-transfer
:title="title"
:from_data="fromData"
:to_data="toData"
@add-btn="add"
@remove-btn="remove"
pid="productionLineId"
:defaultProps="{ label: 'name' }"
height="450px"
:mode="mode"
filter
openAll></tree-transfer>
</el-col>
</el-row>
</el-form>
</template>
<script>
import {
getGroupPlan,
updateGroupPlan,
createGroupPlan,
getGroupPlanTree,
createGroupPlanLine,
updateGroupPlanLine,
getGroupPlanLine,
getLoginUserDeptId,
} from '@/api/base/groupSchedulingPlan';
import { getFactoryPage } from '@/api/core/base/factory';
import { listDept } from '@/api/system/dept';
import { listEnabled } from '@/api/base/groupTeam';
import { listClassesEnabled } from '@/api/base/groupClasses';
import treeTransfer from 'el-tree-transfer';
export default {
components: { treeTransfer },
name: '',
data() {
return {
form: {
id: '',
name: '',
factoryId: '',
teamIdList: [],
classesIdList: [],
remark: '',
},
factoryArr: [], //工厂
teamList: [], //班组
classList: [], //班次
rules: {
name: [{ required: true, message: '请输入计划名称', trigger: 'blur' }],
factoryId: [
{ required: true, message: '请选择工厂', trigger: 'change' },
],
teamIdList: [
{ required: true, message: '请选择相关班组', trigger: 'change' },
],
classesIdList: [
{ required: true, message: '请选择相关班次', trigger: 'change' },
],
},
title: ['待选', '已选'], //标题 类型Array 必填false 默认:["源列表", "目标列表"]
mode: 'transfer',
fromData: [], //左边内容
toData: [], //右边已选内容
};
},
methods: {
init(id) {
this.form.id = id || undefined;
this.fromData = [];
this.toData = [];
this.getArr();
this.$nextTick(() => {
this.$refs['form'].resetFields();
if (this.form.id) {
getGroupPlan(id).then((response) => {
this.form = response.data;
});
}
});
},
getArr() {
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.factoryArr = res.data.list || [];
});
listEnabled().then((res) => {
this.teamList = res.data || [];
});
listClassesEnabled().then((res) => {
this.classList = res.data || [];
});
getGroupPlanTree().then((res) => {
this.fromData = res.data;
this.fromData.forEach((item) => {
item.productionLineId = 0;
});
});
},
// 监听穿梭框组件添加
add(fromData, toData, obj) {
console.log('fromData:', fromData);
console.log('toData:', toData);
},
// 监听穿梭框组件移除
remove(fromData, toData, obj) {
console.log('fromData:', fromData);
console.log('toData:', toData);
},
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.id) {
//编辑
updateGroupPlan({ ...this.form }).then((res) => {
if (res.code === 0) {
this.$modal.msgSuccess('操作成功');
this.$emit('successSubmit');
}
});
} else {
createGroupPlan({ ...this.form }).then((res) => {
if (res.code === 0) {
this.$modal.msgSuccess('操作成功');
this.$emit('successSubmit');
}
});
}
} else {
return false;
}
});
},
formClear() {
this.$refs.form.resetFields();
},
/** 消除组件左边与右边选中数据相同项 */
// 处理过滤数据
getFilterLeftData(data, selData) {
for (let i = data.length - 1; i >= 0; i--) {
for (let j = selData.length - 1; j >= 0; j--) {
if (data[i] && data[i].id === selData[j].id) {
// 当id相等可以删除的情况 即:没有子级可以删除;
if (!data[i].children) {
data.splice(i, 1);
} else {
this.getFilterLeftData(data[i].children, selData[j].children);
}
}
}
}
},
},
};
</script>

View File

@@ -0,0 +1,230 @@
<!--
* @Author: zwq
* @Date: 2024-07-10 11:08:48
* @LastEditors: zwq
* @LastEditTime: 2025-01-14 13:28:40
* @Description:
-->
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<!-- 列表 -->
<base-table
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-props="tableProps"
:table-data="list"
:max-height="tableH">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<pagination
:page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize"
:total="total"
@pagination="getList" />
<!-- 新增 -->
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="centervisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="50%">
<schedulingPlanConfigAdd ref="classList" @successSubmit="successSubmit" />
</base-dialog>
</div>
</template>
<script>
import {
getGroupPlanPage,
deleteGroupPlan,
} from '@/api/base/groupSchedulingPlan';
import schedulingPlanConfigAdd from './components/schedulingPlanConfigAdd.vue';
import tableHeightMixin from '@/mixins/tableHeightMixin';
import { getFactoryPage } from '@/api/core/base/factory';
const tableProps = [
{
prop: 'factoryName',
label: '工厂',
},
{
prop: 'name',
label: '计划名称',
},
{
prop: 'teamName',
label: '班组名称',
},
{
prop: 'classesName',
label: '班次名称',
},
];
export default {
name: 'schedulingPlanConfig',
components: { schedulingPlanConfigAdd },
mixins: [tableHeightMixin],
data() {
return {
formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'input',
label: '计划名称',
placeholder: '计划名称',
param: 'name',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:group-scheduling-plan:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true,
},
],
tableProps,
tableBtn: [
this.$auth.hasPermi('base:group-scheduling-plan:update')
? {
type: 'edit',
btnName: '编辑',
}
: undefined,
this.$auth.hasPermi('base:group-scheduling-plan:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
// 总条数
total: 0,
// 列表
list: [],
// 弹出层标题
addOrEditTitle: '',
// 是否显示弹出层
centervisible: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 20,
name: null,
},
};
},
created() {
this.getList();
this.getPdLineList();
},
methods: {
getPdLineList() {
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.queryParams.pageNo = 1;
this.queryParams.name = val.name || undefined;
this.queryParams.factoryId = val.factoryId || undefined;
this.getList();
break;
default:
this.addOrEditTitle = '新增';
this.centervisible = true;
this.$nextTick(() => {
this.$refs.classList.init();
});
}
},
/** 查询列表 */
getList() {
getGroupPlanPage(this.queryParams).then((res) => {
if (res.code === 0 && res.data.list && res.data.list.length > 0) {
this.list = res.data.list;
this.total = res.data.total;
} else {
this.list = [];
this.total = 0;
}
});
},
handleClick(val) {
switch (val.type) {
case 'edit':
this.addOrEditTitle = '编辑';
this.$nextTick(() => {
this.$refs.classList.init(val.data.id);
});
this.centervisible = true;
break;
default:
this.handleDelete(val.data);
}
},
handleCancel() {
this.$refs.classList.formClear();
this.centervisible = false;
this.addOrEditTitle = '';
},
handleConfirm() {
this.$refs.classList.submitForm();
},
successSubmit() {
this.handleCancel();
this.getList();
},
/** 删除按钮操作 */
handleDelete(row) {
let _this = this;
this.$confirm(`是否确认删除 ${row.name} 的数据项?`, "系统提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(function () {
return deleteGroupPlan(row.id);
})
.then(() => {
_this.getList();
_this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
},
};
</script>

View File

@@ -0,0 +1,340 @@
<!--
* @Author: zwq
* @Date: 2024-07-11 09:30:21
* @LastEditors: zwq
* @LastEditTime: 2025-01-14 15:35:03
* @Description:
-->
<template>
<el-form ref="form" :rules="rules" label-width="110px" :model="form">
<el-row>
<el-col :span="12">
<el-form-item label="工厂" prop="factoryId">
<el-select
v-model="form.factoryId"
filterable
clearable
style="width: 100%"
placeholder="请选择工厂">
<el-option
v-for="item in factoryArr"
:key="item.id"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排班开始日期" prop="startDay">
<el-date-picker
v-model="form.startDay"
type="datetime"
placeholder="选择日期时间"
label-format="yyyy-MM-dd HH:mm:ss"
value-format="timestamp"
style="width: 100%"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排班结束日期" prop="endDay">
<el-date-picker
v-model="form.endDay"
type="datetime"
placeholder="选择日期时间"
label-format="yyyy-MM-dd HH:mm:ss"
value-format="timestamp"
style="width: 100%"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排班计划" prop="planId">
<el-select
v-model="form.planId"
filterable
clearable
@change="setTableArr"
style="width: 100%"
placeholder="请选择排班计划">
<el-option
v-for="item in planArr"
:key="item.id"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<div class="min-title">班组上班顺序</div>
</el-col>
<el-col :span="12">
<el-form-item prop="groupTeamNum">
<el-input-number
v-model="form.groupTeamNum"
:step="1"
:min="1"
step-strictly></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-select
v-model="teamList"
clearable
style="width: 100%; display: inline-block; margin-bottom: 28px"
@change="teamRuleMore"
@visible-change="teamRuleLess"
multiple
placeholder="请选择班组">
<el-option
v-for="item in teamArr"
:key="item.id"
:label="item.name"
:value="item.id">
<span slot="default" style="width: 100%">
{{ item.name }}
<span v-if="teamList.includes(item.id)" style="float: right">
{{ teamList.findIndex((v) => v === item.id) + 1 }}
</span>
</span>
</el-option>
</el-select>
</el-col>
<el-col :span="12">
<el-form-item prop="groupClassesNum">
<el-input-number
v-model="form.groupClassesNum"
:step="1"
:min="1"
step-strictly></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-select
v-model="classesList"
clearable
style="width: 100%; display: inline-block; margin-bottom: 28px"
@change="classesRuleMore"
@visible-change="classesRuleLess"
multiple
placeholder="请选择班次">
<el-option
v-for="item in classesArr"
:key="item.id"
:label="item.name"
:value="item.id">
<span slot="default" style="width: 100%">
{{ item.name }}
<span v-if="classesList.includes(item.id)" style="float: right">
{{ classesList.findIndex((v) => v === item.id) + 1 }}
</span>
</span>
</el-option>
</el-select>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import {
getGroupRule,
updateGroupRule,
createGroupRule,
} from '@/api/base/groupSchedulingRule';
import {
groupPlanList,
groupPlanTeamList,
groupPlanClassesList,
} from '@/api/base/groupSchedulingPlan';
import { getFactoryPage } from '@/api/core/base/factory';
import tableSelect from './tableSelect';
export default {
name: 'schedulingRuleConfigAdd',
data() {
return {
form: {
id: '',
factoryId: '',
startDay: '',
endDay: '',
planId: '',
groupTeamNum: 1,
groupClassesNum: 1,
groupClassesList: [],
groupTeamList: [],
remark: '',
},
factoryArr: [], //工厂
planArr: [], //排班计划数组
classesArr: [],
teamArr: [],
classesList: [],
teamList: [],
rules: {
factoryId: [
{ required: true, message: '请选择工厂', trigger: 'change' },
],
startDay: [
{ required: true, message: '请选择排班开始时间', trigger: 'change' },
],
endDay: [
{ required: true, message: '请选择排班结束时间', trigger: 'change' },
],
planId: [
{ required: true, message: '请选择排班计划', trigger: 'change' },
],
},
};
},
methods: {
init(id) {
this.form = {
id: id || undefined,
factoryId: '',
startDay: '',
endDay: '',
planId: '',
groupClassesList: [],
groupTeamList: [],
remark: '',
};
this.classesList = [];
this.teamList = [];
this.getArr();
this.$nextTick(() => {
this.$refs['form'].resetFields();
if (this.form.id) {
getGroupRule(id).then((response) => {
this.form = response.data;
response.data.teamSequenceList.forEach(item=>{
this.teamList.push(item.teamId)
})
response.data.classesSequenceList.forEach(item=>{
this.classesList.push(item.classesId)
})
this.form.groupTeamNum = response.data.teamSequenceList.length
this.form.groupClassesNum = response.data.classesSequenceList.length
this.getTableArr(response.data.planId);
});
}
});
},
getArr() {
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.factoryArr = res.data.list || [];
});
groupPlanList().then((res) => {
this.planArr = res.data || [];
});
},
setTableArr() {
if (this.form.planId) {
this.getTableArr(this.form.planId);
}
},
async getTableArr(id) {
//获取下拉框
const res0 = await groupPlanClassesList(id);
this.classesArr = res0.data || [];
const res1 = await groupPlanTeamList(id);
this.teamArr = res1.data || [];
},
teamRuleMore() {
if (this.teamList.length > this.form.groupTeamNum) {
this.$message('选择班组数 超过 排班数');
}
},
teamRuleLess(val) {
if (val === false) {
if (this.teamList.length < this.form.groupTeamNum) {
this.$message('选择班组数 小于 排班数');
}
}
},
classesRuleMore() {
if (this.classesList.length > this.form.groupClassesNum) {
this.$message('选择班次数 超过 倒班数');
}
},
classesRuleLess(val) {
if (val === false) {
if (this.classesList.length < this.form.groupClassesNum) {
this.$message('选择班组数 小于 倒班数');
}
}
},
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.teamList.length > this.form.groupTeamNum) {
this.$message('选择班组数 超过 排班数');
return
} else if (this.teamList.length < this.form.groupTeamNum) {
this.$message('选择班组数 小于 排班数');
return
}
if (this.classesList.length > this.form.groupClassesNum) {
this.$message('选择班次数 超过 倒班数');
return
} else if (this.classesList.length < this.form.groupClassesNum) {
this.$message('选择班组数 小于 倒班数');
return
}
this.form.groupTeamList = []
this.teamList.forEach((item,index)=>{
this.form.groupTeamList.push({
teamId: item,
sequence:index+1
})
})
this.form.groupClassesList = []
this.classesList.forEach((item,index)=>{
this.form.groupClassesList.push({
classesId: item,
sequence:index+1
})
})
if (this.form.id) {
//编辑
updateGroupRule({ ...this.form }).then((res) => {
this.$modal.msgSuccess('操作成功');
this.$emit('successSubmit');
});
} else {
createGroupRule({ ...this.form }).then((res) => {
this.$modal.msgSuccess('操作成功');
this.$emit('successSubmit');
});
}
} else {
return false;
}
});
},
formClear() {
this.$refs.form.resetFields();
},
},
};
</script>
<style scoped>
.min-title {
margin-bottom: 5px;
}
.min-title::before {
content: '*';
color: #ff5454;
margin-right: 4px;
}
</style>

View File

@@ -0,0 +1,44 @@
<template>
<div class="tableInner">
<el-select :key="itemProp+list._pageIndex" v-model="list[itemProp]" @change="changeInput">
<el-option
v-for="item in itemProp==='classesId'?list.classesArr:list.teamArr"
:key="item.id"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</div>
</template>
<script>
export default {
name: 'tableSelect',
props: {
injectData: {
type: Object,
default: () => ({}),
},
itemProp: {
type: String,
},
},
data() {
return {
list: this.injectData,
};
},
methods: {
changeInput() {
this.$emit('emitData', this.list);
},
},
};
</script>
<style scoped>
.tableInner >>> .el-input__inner {
color: #409EFF;
border: 1px rgb(232, 231, 231) solid;
padding: 0;
text-align: center;
height: 30px;
}
</style>

View File

@@ -0,0 +1,284 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<!-- 列表 -->
<base-table
:page="queryParams.pageNo"
:limit="queryParams.pageSize"
:table-props="tableProps"
:table-data="list"
:max-height="tableH">
<method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" />
</base-table>
<pagination
:page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize"
:total="total"
@pagination="getList" />
<!-- 新增 -->
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="centervisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="50%">
<schedulingRuleConfigAdd ref="classList" @successSubmit="successSubmit" />
</base-dialog>
</div>
</template>
<script>
import {
getGroupRulePage,
deleteGroupRule,
updateGroupRule,
getGroupRule,
disableGroupRule
} from '@/api/base/groupSchedulingRule';
import schedulingRuleConfigAdd from './components/schedulingRuleConfigAdd.vue';
import { formatDate } from '@/utils';
import tableHeightMixin from '@/mixins/tableHeightMixin';
import { getFactoryPage } from '@/api/core/base/factory';
const tableProps = [
{
prop: 'factoryName',
label: '工厂',
},
{
prop: 'enableTimeStr',
label: '排班日期',
minWidth: 200,
},
{
prop: 'planName',
label: '排班计划',
},
{
prop: 'str',
label: '排班规则',
minWidth: 100,
},
{
prop: 'enabled',
label: '状态',
filter: (val) => (val ? '正常' : '作废'),
},
];
export default {
name: 'schedulingRuleConfig',
components: { schedulingRuleConfigAdd },
mixins: [tableHeightMixin],
data() {
return {
formConfig: [
{
type: 'select',
label: '工厂',
selectOptions: [],
param: 'factoryId',
onchange: true,
},
{
type: 'input',
label: '班次',
placeholder: '班次',
param: 'name',
},
{
type: 'button',
btnName: '查询',
name: 'search',
color: 'primary',
},
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:group-scheduling-rule:create')
? 'button'
: '',
btnName: '新增',
name: 'add',
color: 'success',
plain: true,
},
],
tableProps,
tableBtn: [
this.$auth.hasPermi('base:group-scheduling-rule:cancel')
? {
type: 'cancel',
btnName: '作废',
showParam: {
type: '&',
data: [
{
type: 'unequal',
name: 'enabled',
value: 0,
},
],
},
}
: undefined,
this.$auth.hasPermi('base:group-scheduling-rule:update')
? {
type: 'edit',
btnName: '编辑',
showParam: {
type: '&',
data: [
{
type: 'unequal',
name: 'enabled',
value: 0,
},
],
},
}
: undefined,
this.$auth.hasPermi('base:group-scheduling-rule:delete')
? {
type: 'delete',
btnName: '删除',
}
: undefined,
].filter((v) => v),
// 总条数
total: 0,
// 班次基础信息列表
list: [],
// 弹出层标题
addOrEditTitle: '',
// 是否显示弹出层
centervisible: false,
// 查询参数
queryParams: {
pageNo: 1,
pageSize: 20,
name: null,
},
};
},
created() {
this.getList();
this.getPdLineList();
},
methods: {
getPdLineList() {
const params = {
pageSize: 100,
pageNo: 1,
};
getFactoryPage(params).then((res) => {
this.formConfig[0].selectOptions = res.data.list || [];
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.queryParams.pageNo = 1;
this.queryParams.classesName = val.name || undefined;
this.queryParams.factoryId = val.factoryId || undefined;
this.getList();
break;
default:
this.addOrEditTitle = '新增';
this.centervisible = true;
this.$nextTick(() => {
this.$refs.classList.init();
});
}
},
/** 查询列表 */
getList() {
getGroupRulePage(this.queryParams).then((res) => {
if (res.code === 0 && res.data.list && res.data.list.length > 0) {
res.data.list.map((item) => {
item.enableTimeStr =
formatDate(item.startDay) +
'至' +
(item.endDay ? formatDate(item.endDay) : '永久');
item.str = item.strList.join(',');
});
this.list = res.data.list;
this.total = res.data.total;
} else {
this.list = [];
this.total = 0;
}
});
},
handleClick(val) {
switch (val.type) {
case 'edit':
this.addOrEditTitle = '编辑';
this.$nextTick(() => {
this.$refs.classList.init(val.data.id);
});
this.centervisible = true;
break;
case 'cancel':
this.discard(val.data);
break;
default:
this.handleDelete(val.data);
}
},
handleCancel() {
this.$refs.classList.formClear();
this.centervisible = false;
this.addOrEditTitle = '';
},
handleConfirm() {
this.$refs.classList.submitForm();
},
successSubmit() {
this.handleCancel();
this.getList();
},
discard(row) {
let _this = this
this.$confirm(`是否确认作废 ${row.planName} 的数据项?`, "系统提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
disableGroupRule(row.id).then((response) => {
_this.getList();
_this.$modal.msgSuccess('操作成功');
});
})
.catch(() => {});
},
/** 删除按钮操作 */
handleDelete(row) {
this.$confirm(`是否确认删除 ${row.planName} 的数据项?`, "系统提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(function () {
return deleteGroupRule(row.id);
})
.then(() => {
this.getList();
this.$modal.msgSuccess('删除成功');
})
.catch(() => {});
},
},
};
</script>

View File

@@ -44,7 +44,7 @@
border-radius: 100%; border-radius: 100%;
background: #26b9de; background: #26b9de;
"></span> "></span>
成本管理系统 智能监控分析系统
</p> </p>
</div> </div>
<video <video
@@ -103,37 +103,18 @@
line-height: 54px; line-height: 54px;
letter-spacing: 2px; letter-spacing: 2px;
"> ">
成本管理系统 智能监控分析系统
</h3> </h3>
</h2> </h2>
<!-- 表单 --> <!-- 表单 -->
<div class="form-cont"> <div class="form-cont" style="margin-top: 60px;">
<el-tabs
class="form"
v-model="loginForm.loginType"
style="float: none">
<el-tab-pane label="账号密码登录" name="uname"></el-tab-pane>
<el-tab-pane label="短信验证码登录" name="sms"></el-tab-pane>
</el-tabs>
<div style=""> <div style="">
<el-form <el-form
ref="loginForm" ref="loginForm"
:model="loginForm" :model="loginForm"
:rules="LoginRules" :rules="LoginRules"
class="login-form"> class="login-form">
<el-form-item prop="tenantName" v-if="tenantEnable">
<el-input
v-model="loginForm.tenantName"
type="text"
auto-complete="off"
placeholder="租户">
<!-- <svg-icon
slot="prefix"
icon-class="tree"
class="el-input__icon input-icon" /> -->
</el-input>
</el-form-item>
<!-- 账号密码登录 --> <!-- 账号密码登录 -->
<div v-if="loginForm.loginType === 'uname'"> <div v-if="loginForm.loginType === 'uname'">
<el-form-item prop="username"> <el-form-item prop="username">

View File

@@ -0,0 +1,123 @@
<!--
* @Author: zwq
* @Date: 2021-11-18 14:16:25
* @LastEditors: DY
* @LastEditTime: 2023-10-16 11:16:48
* @Description:
-->
<template>
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="物料名称" prop="materialName">
<el-input v-model="dataForm.materialName" clearable placeholder="请输入物料名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料规格" prop="materialSize">
<el-input v-model="dataForm.materialSize" clearable placeholder="请输入物料规格" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="物料批次" prop="materialDate">
<el-input v-model="dataForm.materialDate" clearable placeholder="请输入物料批次" />
</el-form-item>
</el-col>
<!-- <el-form-item label="启用状态" prop="enabled">
<el-select
v-model="dataForm.enabled"
placeholder="请选择启用状态">
<el-option
v-for="dict in this.getDictDatas(DICT_TYPE.INFRA_BOOLEAN_STRING)"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item> -->
<el-col :span="12">
<el-form-item label="入库数量" prop="materialNum">
<el-input v-model="dataForm.materialNum" clearable placeholder="请输入入库数量" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import basicAdd from './../mixins/basic-add';
import {
createMaterialIssue,
} from '@/api/material/issue';
export default {
mixins: [basicAdd],
data() {
return {
urlOptions: {
isGetCode: false,
// codeURL: getCode,
createURL: createMaterialIssue,
// updateURL: updateFactory,
// infoURL: getFactory,
},
dataForm: {
id: undefined,
materialName: undefined,
materialNum: undefined,
materialDate: undefined,
materialSize: undefined,
operateStatus:undefined
},
dataRule: {
materialName: [{ required: true, message: "物料名称不能为空", trigger: "blur" }],
materialNum: [{ required: true, message: "数量不能为空", trigger: "blur" }],
}
};
},
methods: {
init(operateStatus) {
this.dataForm.operateStatus = operateStatus;
this.visible = true;
this.$nextTick(() => {
this.$refs["dataForm"].resetFields();
// if (this.dataForm.id) {
// this.urlOptions.infoURL(id).then(response => {
// this.dataForm = response.data;
// if (this.setData) {
// this.setDataForm()
// }
// });
// } else {
// if (this.urlOptions.isGetCode) {
// this.getCode()
// }
// }
});
},
dataFormSubmit() {
this.$refs["dataForm"].validate((valid) => {
if (!valid) {
return false;
}
// 修改的提交
// if (this.dataForm.id) {
// this.urlOptions.updateURL(this.dataForm).then(response => {
// this.$modal.msgSuccess("修改成功");
// this.visible = false;
// this.$emit("refreshDataList");
// });
// return;
// }
// 添加的提交
this.urlOptions.createURL(this.dataForm).then(response => {
this.$modal.msgSuccess("新增成功");
this.visible = false;
this.$emit("refreshDataList");
});
});
},
},
};
</script>

View File

@@ -0,0 +1,243 @@
<template>
<div class="app-container">
<search-bar
:formConfigs="formConfig"
ref="searchBarForm"
@headBtnClick="buttonClick" />
<base-table
v-loading="dataListLoading"
:table-props="tableProps"
:page="listQuery.pageNo"
:limit="listQuery.pageSize"
:table-data="tableData">
<!-- <method-btn
v-if="tableBtn.length"
slot="handleBtn"
:width="120"
label="操作"
:method-list="tableBtn"
@clickBtn="handleClick" /> -->
</base-table>
<pagination
:limit.sync="listQuery.pageSize"
:page.sync="listQuery.pageNo"
:total="listQuery.total"
@pagination="getDataList" />
<base-dialog
:dialogTitle="addOrEditTitle"
:dialogVisible="addOrUpdateVisible"
@cancel="handleCancel"
@confirm="handleConfirm"
:before-close="handleCancel"
width="30%">
<add-or-update
ref="addOrUpdate"
@refreshDataList="successSubmit"></add-or-update>
</base-dialog>
</div>
</template>
<script>
import AddOrUpdate from './add-or-updata';
import basicPage from './../mixins/basic-page';
import { parseTime } from './../mixins/code-filter';
import {
getMaterialReceiptIssuePageData,
} from '@/api/material/issue';
const tableProps = [
{
prop: 'materialName',
label: '物料名称'
},
{
prop: 'materialSize',
label: '物料规格'
},
{
prop: 'materialDate',
label: '物料批次'
},
{
prop: 'operateStatus',
label: '操作状态',
filter: (val) => ['', '入库', '出库'][val]
},
{
prop: 'materialNum',
label: '出入库数量',
// filter: (val) => ['', '入库', '出库', '移库'][val]
},
{
prop: 'createTime',
label: '操作时间',
filter: parseTime
},
{
prop: 'creator',
label: '操作人',
// filter: parseTime
},
];
export default {
mixins: [basicPage],
data() {
return {
urlOptions: {
getDataListURL: getMaterialReceiptIssuePageData,
// deleteURL: deleteFactory,
// exportURL: exportFactoryExcel,
},
operateStatus:undefined,
tableProps,
// tableBtn: [
// this.$auth.hasPermi(`base:factory:update`)
// ? {
// type: 'edit',
// btnName: '编辑',
// }
// : undefined,
// this.$auth.hasPermi(`base:factory:delete`)
// ? {
// type: 'delete',
// btnName: '删除',
// }
// : undefined,
// ].filter((v)=>v),
tableData: [],
formConfig: [
{
type: 'input',
label: '物料名称',
placeholder: '物料名称',
param: 'materialName',
},
{
type: 'input',
label: '操作人',
placeholder: '操作人',
param: 'operateName',
},
{
type: 'select',
label: '操作状态',
placeholder: '操作状态',
selectOptions: [{
id: 1,
name:'入库'
},
{
id: 2,
name: '出库'
}],
param: 'operateStatus',
},
{
type: 'datePicker',
label: '操作时间',
dateType: 'daterange',
format: 'yyyy-MM-dd',
valueFormat: 'timestamp',
rangeSeparator: '-',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
param: 'timeVal',
},
{
type: this.$auth.hasPermi('base:material-warehouse-his:query') ? 'button' : '',
btnName: '搜索',
name: 'search',
color: 'primary',
},
// {
// type: 'separate',
// },
// {
// type: 'button',
// btnName: '重置',
// name: 'reset',
// },
{
type: 'separate',
},
{
type: this.$auth.hasPermi('base:material-warehouse-his:create') ? 'button' : '',
btnName: '入库',
name: 'receipt',
color: 'success',
plain: true,
},
{
type: this.$auth.hasPermi('base:material-warehouse-his:create') ? 'button' : '',
btnName: '出库',
name: 'issue',
color: 'success',
plain: true,
},
// {
// type: this.$auth.hasPermi('base:factory:create') ? 'separate' : '',
// },
// {
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
// btnName: '导出',
// name: 'export',
// color: 'warning',
// },
],
};
},
components: {
AddOrUpdate,
},
created() {},
methods: {
addOrUpdateHandle() {
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init(this.operateStatus);
});
},
buttonClick(val) {
switch (val.btnName) {
case 'search':
this.listQuery.pageNo = 1;
this.listQuery.pageSize = 10;
this.listQuery.operateName = val.operateName ? val.operateName :undefined;
this.listQuery.operateTimeStart = val.timeVal? val.timeVal[0] :undefined;
this.listQuery.operateTimeEnd = val.timeVal ? val.timeVal[1] : undefined;
this.listQuery.materialName = val.materialName ? val.materialName : undefined;
this.listQuery.operateStatus = val.operateStatus ? val.operateStatus : undefined;
this.getDataList();
break;
case 'reset':
this.$refs.searchBarForm.resetForm();
this.listQuery = {
pageSize: 10,
pageNo: 1,
total: 1,
};
this.getDataList();
break;
case 'receipt':
this.addOrEditTitle = '入库';
this.addOrUpdateVisible = true;
this.operateStatus = 1
this.addOrUpdateHandle();
break;
case 'issue':
this.addOrEditTitle = '出库';
this.addOrUpdateVisible = true;
this.operateStatus = 2
this.addOrUpdateHandle();
break;
case 'export':
this.handleExport();
break;
default:
console.log(val);
}
},
},
};
</script>

View File

@@ -0,0 +1,100 @@
/*
* @Author: zwq
* @Date: 2022-08-24 11:19:43
* @LastEditors: zwq
* @LastEditTime: 2023-08-03 14:21:04
* @Description:
*/
export default {
data() {
/* eslint-disable */
return {
urlOptions: {
createURL: '',
updateURL: '',
infoURL: '',
codeURL: '',
getOption: false,
isGetCode: false,
optionArrUrl: [],
optionArr: {}
},
visible: false,
setData: false
}
},
created() {
},
activated() {
},
methods: {
init(id) {
this.dataForm.id = id || "";
this.visible = true;
if (this.urlOptions.getOption) {
this.getArr()
}
this.$nextTick(() => {
this.$refs["dataForm"].resetFields();
if (this.dataForm.id) {
this.urlOptions.infoURL(id).then(response => {
this.dataForm = response.data;
if (this.setData) {
this.setDataForm()
}
});
} else {
if (this.urlOptions.isGetCode) {
this.getCode()
}
}
});
},
getCode() {
this.urlOptions.codeURL()
.then(({ data: res }) => {
this.dataForm.code = res;
})
.catch(() => {});
},
getArr() {
const params = {
pageSize: 100,
pageNo: 1,
}
this.urlOptions.optionArrUrl.forEach((item, index) => {
item(params).then(({ data: res }) => {
this.$set(this.urlOptions.optionArr, `arr${index}`, res.list)
})
.catch(() => {
});
});
},
// 表单提交
dataFormSubmit() {
this.$refs["dataForm"].validate((valid) => {
if (!valid) {
return false;
}
// 修改的提交
if (this.dataForm.id) {
this.urlOptions.updateURL(this.dataForm).then(response => {
this.$modal.msgSuccess("修改成功");
this.visible = false;
this.$emit("refreshDataList");
});
return;
}
// 添加的提交
this.urlOptions.createURL(this.dataForm).then(response => {
this.$modal.msgSuccess("新增成功");
this.visible = false;
this.$emit("refreshDataList");
});
});
},
formClear() {
this.$refs.dataForm.resetFields()
}
}
}

View File

@@ -0,0 +1,168 @@
/*
* @Author: zwq
* @Date: 2022-08-24 11:19:43
* @LastEditors: DY
* @LastEditTime: 2023-09-21 16:02:07
* @Description:
*/
export default {
data() {
/* eslint-disable */
return {
urlOptions: {
getDataListURL: '',
deleteURL: '',
statusUrl: '',
exportURL: ''
},
tableData: [],
listQuery: {
pageSize: 10,
pageNo: 1,
total: 1,
},
exportLoading: false,
dataListLoading: false,
addOrEditTitle: '',
addOrUpdateVisible: false,
}
},
created() {
},
mounted() {
this.getDataList()
},
methods: {
// 获取数据列表
getDataList() {
this.dataListLoading = true;
this.urlOptions.getDataListURL(this.listQuery).then(response => {
this.tableData = response.data.list;
this.listQuery.total = response.data.total;
this.dataListLoading = false;
});
},
// 每页数
sizeChangeHandle(val) {
this.listQuery.pageSize = val;
this.listQuery.pageNo = 1;
this.getDataList();
},
// 当前页
currentChangeHandle(val) {
this.listQuery.pageNo = val;
this.getDataList();
},
// 新增 / 修改
addOrUpdateHandle(id) {
this.addOrUpdateVisible = true;
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id);
});
},
cancel(id) {
this.$refs["popover-" + id].showPopper = false;
},
//改变状态
changeStatus(id) {
this.$http
.post(this.urlOptions.statusUrl, { id })
.then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.warning(res.msg);
}
this.$refs["popover-" + id].showPopper = false;
this.$message({
message: this.$t("prompt.success"),
type: "success",
duration: 500,
onClose: () => {
this.getDataList();
},
});
})
.catch(() => { });
},
//tableBtn点击
handleClick(val) {
if (val.type === "edit") {
this.addOrUpdateVisible = true;
this.addOrEditTitle = "编辑";
this.$nextTick(() => {
this.$refs.addOrUpdate.init(val.data.id);
});
} else if (val.type === "delete") {
this.deleteHandle(val.data.id, val.data.name, val.data._pageIndex)
} else if (val.type === "change") {
this.changeStatus(val.data.id)
} else {
this.otherMethods(val)
}
},
// 删除
deleteHandle(id, name, index) {
this.$confirm(`确定对${name ? '[名称=' + name + ']' : '[序号=' + index + ']'}进行删除操作?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.urlOptions.deleteURL(id).then(({ data }) => {
this.$message({
message: "操作成功",
type: "success",
duration: 1500,
onClose: () => {
this.getDataList();
},
});
});
})
.catch(() => { });
},
//search-bar点击
buttonClick(val) {
switch (val.btnName) {
case "search":
this.listQuery.xm1 = val.xm1;
this.listQuery.xm2 = val.xm2;
this.listQuery.pageNo = 1;
this.getDataList();
break;
case "add":
this.addOrEditTitle = '新增'
this.addOrUpdateVisible = true;
this.addOrUpdateHandle()
break;
default:
console.log(val)
}
},
handleCancel() {
this.$refs.addOrUpdate.formClear()
this.addOrUpdateVisible = false
this.addOrEditTitle = ''
},
handleConfirm() {
this.$refs.addOrUpdate.dataFormSubmit()
},
successSubmit() {
this.handleCancel()
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(() => { });
}
}
}

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