Merge pull request '新增设备总览透光率产线产品监控等' (#462) from projects/qhd-line-zhp into projects/qhd-line-test
Reviewed-on: #462
This commit is contained in:
2
.env.dev
2
.env.dev
@@ -13,6 +13,8 @@ VUE_APP_TITLE = 智能监控分析系统
|
||||
|
||||
# 芋道管理系统/开发环境
|
||||
VUE_APP_BASE_API = 'http://172.16.32.79:48080'
|
||||
# VUE_APP_BASE_API = 'http://line.kszny.picaiba.com'
|
||||
|
||||
|
||||
# 路由懒加载
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||
|
||||
@@ -59,3 +59,33 @@ export function getEquipmentAll() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
export function getTree(query) {
|
||||
return request({
|
||||
url: '/base/factory/getTreeSimple',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
export function getEquipmentOverall(data) {
|
||||
return request({
|
||||
url: '/monitoring/equipment-overall/get',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getParamMonitor(data) {
|
||||
return request({
|
||||
url: '/monitoring/equipment-monitor/paramMonitor',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
export function getAlarmDet(data) {
|
||||
return request({
|
||||
url: 'monitoring/equipment-overall/alarmDet',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,9 +39,10 @@ export function getNewCTCharts(data) {
|
||||
})
|
||||
}
|
||||
// 获取产线平衡分析数据设备list(new)
|
||||
export function getNewCTDet(id) {
|
||||
export function getNewCTDet(data) {
|
||||
return request({
|
||||
url: '/analysis/production-analysis/getNewCTDet?lineId='+id,
|
||||
method: 'get',
|
||||
})
|
||||
url: '/analysis/production-analysis/getNewCTDet',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,31 +5,31 @@
|
||||
* @LastEditors: zwq
|
||||
* @Description:
|
||||
*/
|
||||
import request from '@/utils/request'
|
||||
import request from '@/utils/request';
|
||||
|
||||
// 获得工厂分页
|
||||
export function getPdlAutoReport(data) {
|
||||
return request({
|
||||
url: '/monitoring/production-monitor/getPdlAutoReport',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
// 获得所有工厂产线列表
|
||||
export function getPdList(id) {
|
||||
return request({
|
||||
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
|
||||
})
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
// 获得产品自动报表
|
||||
@@ -37,23 +37,77 @@ export function getProductAuto(data) {
|
||||
return request({
|
||||
url: '/monitoring/production-monitor/getProcessAutoReportNew',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getPdlAutoReportNewSearchNow(data) {
|
||||
return request({
|
||||
url: '/monitoring/production-monitor/getPdlAutoReportNewSearchNow',
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 60000,
|
||||
});
|
||||
}
|
||||
|
||||
export function getPdlAutoReportNewSearchLastGroup(data) {
|
||||
return request({
|
||||
url: '/monitoring/production-monitor/getPdlAutoReportNewSearchLastGroup',
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 60000,
|
||||
});
|
||||
}
|
||||
|
||||
// 班组自动报表分页
|
||||
export function getTeamReportPage(data) {
|
||||
return request({
|
||||
url: '/monitoring/team-auto-report/page',
|
||||
url: '/monitoring/group-off-record/page',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
// 班组自动报表分页详细
|
||||
export function getTeamReportPageDet(id) {
|
||||
return request({
|
||||
url: '/monitoring/team-auto-report/pageDet?id=' + id,
|
||||
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',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 获取产品当班数据
|
||||
export function getProcessAutoReportGroup(data) {
|
||||
return request({
|
||||
url: '/monitoring/production-monitor/getProcessAutoReportGroup',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
// 获取产品当天数据
|
||||
export function getProcessAutoReportDay(data) {
|
||||
return request({
|
||||
url: '/monitoring/production-monitor/getProcessAutoReportDay',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
// 获取产品历史数据
|
||||
export function getProcessAutoReportNew(data) {
|
||||
return request({
|
||||
url: '/monitoring/production-monitor/getProcessAutoReportNew',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,3 +14,78 @@ export function getSectionDataSearch(data) {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
// 获取下片日志分页数据
|
||||
export function getDownLogPage(data) {
|
||||
return request({
|
||||
url: '/base/down-log/page',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
// 获取下片日志历史数据
|
||||
export function getDownLogHisData(data) {
|
||||
return request({
|
||||
url: '/base/down-log/pagehis',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 导出下片日志Excel
|
||||
export function exportDownLogData(query) {
|
||||
return request({
|
||||
url: '/base/down-log/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 获得所有工厂产线列表
|
||||
export function getPdList() {
|
||||
return request({
|
||||
url: '/base/production-line/listAll',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 获得玻璃型号列表
|
||||
export function getThick() {
|
||||
return request({
|
||||
url: '/base/down-log/thick',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
// 获得原片报表
|
||||
export function getCostOriginRadioHisData(data) {
|
||||
return request({
|
||||
url: '/monitoring/cost-origin-ratio-his/page',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
// 修改原片报表
|
||||
export function editCostOriginRadioHisData(data) {
|
||||
return request({
|
||||
url: '/monitoring/cost-origin-ratio-his/update',
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
// 导出原片报表
|
||||
export function exportCostOriginRadioHisData(data) {
|
||||
return request({
|
||||
url: '/monitoring/cost-origin-ratio-his/export-excel',
|
||||
method: 'get',
|
||||
params: data,
|
||||
responseType: 'blob',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
56
src/api/monitoring/defectSummary.js
Normal file
56
src/api/monitoring/defectSummary.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建能源监控配置
|
||||
export function getDefectSummaryTable(data) {
|
||||
return request({
|
||||
url: '/extend/check-gaozhun-record/defectSummaryTable',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
export function getTranslucentPage(data) {
|
||||
return request({
|
||||
url: '/monitoring/translucent/page',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function exportTranslucent(data) {
|
||||
return request({
|
||||
url: '/monitoring/translucent/export-excel',
|
||||
method: 'get',
|
||||
params: data,
|
||||
responseType: 'blob',
|
||||
});
|
||||
}
|
||||
|
||||
export function getDefectAnalysis(data) {
|
||||
return request({
|
||||
url: '/extend/check-gaozhun-record/defectAnalysis',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getSectionDefect(data) {
|
||||
return request({
|
||||
url: '/extend/check-gaozhun-record/sectionDefect',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
export function getDefectSummaryChart(data) {
|
||||
return request({
|
||||
url: '/extend/check-gaozhun-record/defectSummaryChart',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
export function getDefectSummaryDet(data) {
|
||||
return request({
|
||||
url: '/extend/check-gaozhun-record/defectSummaryDet',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
BIN
src/assets/images/equipmentNum.png
Normal file
BIN
src/assets/images/equipmentNum.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/images/equipmentNumImg.png
Normal file
BIN
src/assets/images/equipmentNumImg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.1 KiB |
BIN
src/assets/images/runNum.png
Normal file
BIN
src/assets/images/runNum.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/images/runNumImg.png
Normal file
BIN
src/assets/images/runNumImg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
BIN
src/assets/images/stopNum.png
Normal file
BIN
src/assets/images/stopNum.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/images/stopNumImg.png
Normal file
BIN
src/assets/images/stopNumImg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
@@ -54,7 +54,7 @@ export default {
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.currentMenu = this.menus[0];
|
||||
// this.currentMenu = this.menus[0];
|
||||
},
|
||||
watch: {
|
||||
currentMenu(val) {
|
||||
|
||||
@@ -6,99 +6,43 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="form"
|
||||
:label-width="`${labelWidth}px`"
|
||||
:size="size"
|
||||
:label-position="labelPosition"
|
||||
<el-form ref="form" :model="form" :label-width="`${labelWidth}px`" :size="size" :label-position="labelPosition"
|
||||
v-loading="formLoading">
|
||||
<el-row :gutter="20" v-for="(row, rindex) in rows" :key="rindex">
|
||||
<el-col v-for="col in row" :key="col.label" :span="24 / row.length">
|
||||
<el-form-item :label="col.label" :prop="col.prop" :rules="col.rules">
|
||||
<el-input
|
||||
v-if="col.input"
|
||||
v-model="form[col.prop]"
|
||||
@change="$emit('update', form)"
|
||||
:placeholder="`请输入${col.label}`"
|
||||
v-bind="col.bind" />
|
||||
<el-input
|
||||
v-if="col.textarea"
|
||||
type="textarea"
|
||||
v-model="form[col.prop]"
|
||||
@change="$emit('update', form)"
|
||||
:placeholder="`请输入${col.label}`"
|
||||
v-bind="col.bind" />
|
||||
<el-select
|
||||
v-if="col.select"
|
||||
v-model="form[col.prop]"
|
||||
:placeholder="`请选择${col.label}`"
|
||||
@change="$emit('update', form)"
|
||||
v-bind="col.bind">
|
||||
<el-option
|
||||
v-for="opt in optionListOf[col.prop]"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value" />
|
||||
<el-input v-if="col.input" v-model="form[col.prop]" @change="$emit('update', form)"
|
||||
:placeholder="`请输入${col.label}`" v-bind="col.bind" />
|
||||
<el-input v-if="col.textarea" type="textarea" v-model="form[col.prop]" @change="$emit('update', form)"
|
||||
:placeholder="`请输入${col.label}`" v-bind="col.bind" />
|
||||
<el-select v-if="col.select" v-model="form[col.prop]" :placeholder="`请选择${col.label}`"
|
||||
@change="$emit('update', form)" v-bind="col.bind">
|
||||
<el-option v-for="opt in optionListOf[col.prop]" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
<el-date-picker
|
||||
v-if="col.datetime"
|
||||
v-model="form[col.prop]"
|
||||
type="datetime"
|
||||
:placeholder="`请选择${col.label}`"
|
||||
value-format="timestamp"
|
||||
v-bind="col.bind"></el-date-picker>
|
||||
<el-switch
|
||||
v-if="col.switch"
|
||||
v-model="form[col.prop]"
|
||||
active-color="#0b58ff"
|
||||
inactive-color="#e1e1e1"
|
||||
v-bind="col.bind"></el-switch>
|
||||
<component
|
||||
v-if="col.subcomponent"
|
||||
:key="col.key"
|
||||
:is="col.subcomponent"
|
||||
:inlineStyle="col.style"></component>
|
||||
<el-date-picker v-if="col.datetime" v-model="form[col.prop]" type="datetime" :placeholder="`请选择${col.label}`"
|
||||
value-format="timestamp" v-bind="col.bind"></el-date-picker>
|
||||
<el-switch v-if="col.switch" v-model="form[col.prop]" active-color="#0b58ff" inactive-color="#e1e1e1"
|
||||
v-bind="col.bind" @change="handleSwitchChange(col.prop)"></el-switch>
|
||||
<component v-if="col.subcomponent" :key="col.key" :is="col.subcomponent" :inlineStyle="col.style"></component>
|
||||
|
||||
<div
|
||||
class="upload-area"
|
||||
:class="uploadOpen ? '' : 'height-48'"
|
||||
ref="uploadArea"
|
||||
v-if="col.upload">
|
||||
<div class="upload-area" :class="uploadOpen ? '' : 'height-48'" ref="uploadArea" v-if="col.upload">
|
||||
<span class="close-icon" :class="uploadOpen ? 'open' : ''">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-arrow-right"
|
||||
@click="handleFilesOpen" />
|
||||
<el-button type="text" icon="el-icon-arrow-right" @click="handleFilesOpen" />
|
||||
</span>
|
||||
<!-- :file-list="uploadedFileList" -->
|
||||
<el-upload
|
||||
class="upload-in-dialog"
|
||||
v-if="col.upload"
|
||||
:action="uploadUrl"
|
||||
:headers="uploadHeaders"
|
||||
:show-file-list="false"
|
||||
icon="el-icon-upload2"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="handleUploadSuccess"
|
||||
v-bind="col.bind">
|
||||
<el-upload class="upload-in-dialog" v-if="col.upload" :action="uploadUrl" :headers="uploadHeaders"
|
||||
:show-file-list="false" icon="el-icon-upload2" :before-upload="beforeUpload"
|
||||
:on-success="handleUploadSuccess" v-bind="col.bind">
|
||||
<el-button size="mini" :disabled="col.bind?.disabled || false">
|
||||
<svg-icon
|
||||
icon-class="icon-upload"
|
||||
style="color: inherit"></svg-icon>
|
||||
<svg-icon icon-class="icon-upload" style="color: inherit"></svg-icon>
|
||||
上传文件
|
||||
</el-button>
|
||||
<div class="el-upload__tip" slot="tip" v-if="col.uploadTips">
|
||||
{{ col.uploadTips || '只能上传jpg/png文件, 大小不超过2MB' }}
|
||||
</div>
|
||||
</el-upload>
|
||||
<uploadedFile
|
||||
class="file"
|
||||
v-for="file in form[col.prop] || []"
|
||||
:file="file"
|
||||
:key="file.fileUrl"
|
||||
@delete="handleDeleteFile(file)"
|
||||
@Preview="handlePreview(file)" />
|
||||
<uploadedFile class="file" v-for="file in form[col.prop] || []" :file="file" :key="file.fileUrl"
|
||||
@delete="handleDeleteFile(file)" @Preview="handlePreview(file)" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -135,6 +79,7 @@ const uploadedFile = {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
|
||||
handleDelete() {
|
||||
this.$emit('delete', this.file);
|
||||
},
|
||||
@@ -252,6 +197,11 @@ export default {
|
||||
this.handleOptions();
|
||||
},
|
||||
methods: {
|
||||
handleSwitchChange(prop) {
|
||||
// 触发 update 事件,将最新的 form 数据传递给父组件
|
||||
this.$emit('update', { ...this.form });
|
||||
console.log(`switch ${prop} 变化:`, this.form[prop]);
|
||||
},
|
||||
/** 模拟透传 ref */
|
||||
validate(cb) {
|
||||
return this.$refs.form.validate(cb);
|
||||
@@ -449,6 +399,7 @@ export default {
|
||||
.dialog__upload_component__close {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.dialog__upload_component__close:hover {
|
||||
/* color: #777; */
|
||||
color: red;
|
||||
|
||||
@@ -6,14 +6,8 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
:visible="visible"
|
||||
:show-close="false"
|
||||
:wrapper-closable="false"
|
||||
class="drawer"
|
||||
custom-class="mes-drawer"
|
||||
:size="size || '50%'"
|
||||
@closed="$emit('destroy')">
|
||||
<el-drawer :visible="visible" :show-close="false" :wrapper-closable="false" class="drawer" custom-class="mes-drawer"
|
||||
:size="size || '50%'" @closed="$emit('destroy')">
|
||||
<SmallTitle slot="title">
|
||||
{{
|
||||
mode.includes('detail')
|
||||
@@ -29,9 +23,7 @@
|
||||
<section v-for="(section, index) in sections" :key="section.key">
|
||||
<SmallTitle v-if="index != 0">{{ section.name }}</SmallTitle>
|
||||
|
||||
<div
|
||||
class="form-part"
|
||||
v-if="section.key == 'base'"
|
||||
<div class="form-part" v-if="section.key == 'base'"
|
||||
style="border-bottom: 1px solid #dfdfdf; margin-bottom: 24px">
|
||||
<el-skeleton v-if="!showForm" animated />
|
||||
<!-- <BaseInfoForm
|
||||
@@ -45,9 +37,7 @@
|
||||
<!-- if -->
|
||||
<el-row v-if="mode.includes('detail')" style="margin-bottom: 24px">
|
||||
<el-col :span="8">
|
||||
<div
|
||||
class="title"
|
||||
style="font-weight: 700; font-size: 16px; margin: 8px 0">
|
||||
<div class="title" style="font-weight: 700; font-size: 16px; margin: 8px 0">
|
||||
设备名
|
||||
</div>
|
||||
<div class="value" style="font-size: 14px">
|
||||
@@ -55,9 +45,7 @@
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div
|
||||
class="title"
|
||||
style="font-weight: 700; font-size: 16px; margin: 8px 0">
|
||||
<div class="title" style="font-weight: 700; font-size: 16px; margin: 8px 0">
|
||||
关联表名
|
||||
</div>
|
||||
<div class="value" style="font-size: 14px">
|
||||
@@ -69,37 +57,16 @@
|
||||
<el-row v-else style="margin-bottom: 24px" :gutter="20">
|
||||
<el-form ref="form" :model="form">
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
class="title"
|
||||
label="设备名"
|
||||
style="font-size: 16px; margin: 8px 0">
|
||||
<el-select
|
||||
v-model="form.equipmentId"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择设备">
|
||||
<el-option
|
||||
v-for="eq in eqList"
|
||||
:key="eq.id"
|
||||
:label="eq.name"
|
||||
:value="eq.id"></el-option>
|
||||
<el-form-item class="title" label="设备名" style="font-size: 16px; margin: 8px 0">
|
||||
<el-select v-model="form.equipmentId" filterable clearable placeholder="请选择设备">
|
||||
<el-option v-for="eq in eqList" :key="eq.id" :label="eq.name" :value="eq.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item
|
||||
class="title"
|
||||
label="设备关联表名"
|
||||
style="font-size: 16px; margin: 8px 0">
|
||||
<el-select
|
||||
v-model="form.plcId"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择关联表">
|
||||
<el-option
|
||||
v-for="plc in plcList"
|
||||
:key="plc.id"
|
||||
:label="plc.plcTableName"
|
||||
<el-form-item class="title" label="设备关联表名" style="font-size: 16px; margin: 8px 0">
|
||||
<el-select v-model="form.plcId" filterable clearable placeholder="请选择关联表">
|
||||
<el-option v-for="plc in plcList" :key="plc.id" :label="plc.plcTableName"
|
||||
:value="plc.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -108,73 +75,43 @@
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="section.key == 'attrs'"
|
||||
style="position: relative; margin-top: 12px">
|
||||
<div
|
||||
v-if="!mode.includes('detail')"
|
||||
style="position: absolute; top: -40px; right: 0">
|
||||
<div v-if="section.key == 'attrs'" style="position: relative; margin-top: 12px">
|
||||
<div v-if="!mode.includes('detail')" style="position: absolute; top: -40px; right: 0">
|
||||
<el-button @click="handleAddAttr" type="text">
|
||||
<i class="el-icon-plus"></i>
|
||||
添加参数
|
||||
</el-button>
|
||||
</div>
|
||||
<base-table
|
||||
v-loading="attrListLoading"
|
||||
:table-props="section.props"
|
||||
:page="attrQuery?.params.pageNo || 1"
|
||||
:limit="attrQuery?.params.pageSize || 10"
|
||||
:table-data="list"
|
||||
@emitFun="handleEmitFun">
|
||||
<base-table v-loading="attrListLoading" :table-props="section.props" :page="attrQuery?.params.pageNo || 1"
|
||||
:limit="attrQuery?.params.pageSize || 10" :table-data="list" @emitFun="handleEmitFun">
|
||||
<!-- :add-button-show="mode.includes('detail') ? null : '添加属性'"
|
||||
@emitButtonClick="handleAddAttr" -->
|
||||
<method-btn
|
||||
v-if="section.tableBtn && !mode.includes('detail')"
|
||||
slot="handleBtn"
|
||||
label="操作"
|
||||
:method-list="tableBtn"
|
||||
@clickBtn="handleTableBtnClick" />
|
||||
<method-btn v-if="section.tableBtn && !mode.includes('detail')" slot="handleBtn" label="操作"
|
||||
:method-list="tableBtn" @clickBtn="handleTableBtnClick" />
|
||||
</base-table>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="attrQuery.params.pageNo"
|
||||
:limit.sync="attrQuery.params.pageSize"
|
||||
@pagination="getAttrList" />
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="attrQuery.params.pageNo"
|
||||
:limit.sync="attrQuery.params.pageSize" @pagination="getAttrList" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="drawer-body__footer">
|
||||
<el-button style="" @click="handleCancel">取消</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
v-if="!mode.includes('detail')"
|
||||
@click="handleSave">
|
||||
<el-button type="primary" v-if="!mode.includes('detail')" @click="handleSave">
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 属性对话框 -->
|
||||
<base-dialog
|
||||
v-if="sections[1].allowAdd"
|
||||
:dialogTitle="attrTitle"
|
||||
:dialogVisible="attrFormVisible"
|
||||
width="45%"
|
||||
:append-to-body="true"
|
||||
custom-class="baseDialog"
|
||||
@close="closeAttrForm"
|
||||
@cancel="closeAttrForm"
|
||||
<base-dialog v-if="sections[1].allowAdd" :dialogTitle="attrTitle" :dialogVisible="attrFormVisible" width="45%"
|
||||
:append-to-body="true" custom-class="baseDialog" @close="closeAttrForm" @cancel="closeAttrForm"
|
||||
@confirm="submitAttrForm">
|
||||
<!-- :disabled="mode.includes('detail')" -->
|
||||
<DialogForm
|
||||
v-if="attrFormVisible"
|
||||
ref="attrForm"
|
||||
v-model="attrForm"
|
||||
:rows="attrRows" />
|
||||
<DialogForm v-if="attrFormVisible" ref="attrForm" v-model="attrForm" :data-form="attrForm" :rows="attrRows"
|
||||
@update="handleAttrFormUpdate" />
|
||||
</base-dialog>
|
||||
</el-drawer>
|
||||
</template>
|
||||
@@ -233,6 +170,8 @@ export default {
|
||||
description: '',
|
||||
remark: '',
|
||||
alarmContent: '',
|
||||
displayTip: false,
|
||||
alarmTip: false,
|
||||
},
|
||||
attrFormVisible: false,
|
||||
attrRows: [
|
||||
@@ -343,6 +282,26 @@ export default {
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
switch: true,
|
||||
label: '是否展示',
|
||||
prop: 'displayTip',
|
||||
bind: {
|
||||
'active-value': true,
|
||||
'inactive-value': false,
|
||||
},
|
||||
},
|
||||
{
|
||||
switch: true,
|
||||
label: '超出阈值是否报警',
|
||||
prop: 'alarmTip',
|
||||
bind: {
|
||||
'active-value': true,
|
||||
'inactive-value': false,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
input: true,
|
||||
@@ -437,6 +396,23 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleAttrFormUpdate(updatedForm) {
|
||||
console.log('updatedForm', updatedForm);
|
||||
|
||||
// 只同步需要的字段,避免覆盖其他数据
|
||||
this.attrForm = {
|
||||
...this.attrForm,
|
||||
...updatedForm,
|
||||
// 确保开关值是布尔类型(双重保险)
|
||||
displayTip: Boolean(updatedForm.displayTip),
|
||||
alarmTip: Boolean(updatedForm.alarmTip),
|
||||
collection: Number(updatedForm.collection) // 采集开关保持数字类型
|
||||
};
|
||||
console.log('开关值同步:', {
|
||||
displayTip: this.attrForm.displayTip,
|
||||
alarmTip: this.attrForm.alarmTip
|
||||
});
|
||||
},
|
||||
handleTableBtnClick({ type, data }) {
|
||||
switch (type) {
|
||||
case 'edit':
|
||||
@@ -503,6 +479,7 @@ export default {
|
||||
plcParamName: '',
|
||||
unit: '',
|
||||
collection: 1,
|
||||
|
||||
minValue: '',
|
||||
maxValue: '',
|
||||
defaultValue: '',
|
||||
@@ -511,6 +488,8 @@ export default {
|
||||
equipmentParamType: '',
|
||||
productionParamType: '',
|
||||
alarmContent: '',
|
||||
displayTip: false,
|
||||
alarmTip: false,
|
||||
};
|
||||
this.attrTitle = '添加参数绑定信息';
|
||||
this.attrFormVisible = true;
|
||||
@@ -524,7 +503,14 @@ export default {
|
||||
params: { id: attrId },
|
||||
});
|
||||
if (res.code == 0) {
|
||||
this.attrForm = res.data;
|
||||
console.log('res.data', res.data);
|
||||
|
||||
this.attrForm = {
|
||||
...res.data,
|
||||
// // 强制转为数字类型,避免字符串类型导致绑定失败
|
||||
// displayTip: Number(res.data.displayTip) || 0,
|
||||
// alarmTip: Number(res.data.alarmTip) || 0
|
||||
};
|
||||
this.attrTitle = '编辑参数绑定信息';
|
||||
this.attrFormVisible = true;
|
||||
}
|
||||
@@ -564,6 +550,7 @@ export default {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
console.log('this.attrForm', this.attrForm);
|
||||
|
||||
const isEdit = this.attrForm.id != null;
|
||||
this.attrFormSubmitting = true;
|
||||
@@ -583,8 +570,9 @@ export default {
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
onClose: () => {
|
||||
this.getAttrList();
|
||||
this.shouldRefreshPageView = true;
|
||||
this.getAttrList();
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,28 +6,14 @@
|
||||
* @Description:
|
||||
-->
|
||||
<template>
|
||||
<el-form
|
||||
:model="dataForm"
|
||||
:rules="dataRule"
|
||||
ref="dataForm"
|
||||
v-if="visible"
|
||||
@keyup.enter.native="dataFormSubmit()"
|
||||
label-width="100px"
|
||||
label-position="top">
|
||||
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" v-if="visible" @keyup.enter.native="dataFormSubmit()"
|
||||
label-width="100px" label-position="top">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="原料名称" prop="materialId">
|
||||
<el-select
|
||||
v-model="dataForm.materialId"
|
||||
filterable
|
||||
@change="setCode"
|
||||
:style="{ width: '100%' }"
|
||||
<el-select v-model="dataForm.materialId" filterable @change="setCode" :style="{ width: '100%' }"
|
||||
placeholder="请选择原料名称">
|
||||
<el-option
|
||||
v-for="item in MaterialList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"></el-option>
|
||||
<el-option v-for="item in MaterialList" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -38,41 +24,25 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="生效开始时间" prop="startTime">
|
||||
<el-date-picker
|
||||
v-model="dataForm.startTime"
|
||||
type="date"
|
||||
value-format="timestamp"
|
||||
:style="{ width: '100%' }"
|
||||
<el-date-picker v-model="dataForm.startTime" type="date" value-format="timestamp" :style="{ width: '100%' }"
|
||||
placeholder="选择开始时间"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="生效结束时间" prop="endTime">
|
||||
<el-date-picker
|
||||
v-model="dataForm.endTime"
|
||||
type="date"
|
||||
value-format="timestamp"
|
||||
:style="{ width: '100%' }"
|
||||
<el-date-picker v-model="dataForm.endTime" type="date" value-format="timestamp" :style="{ width: '100%' }"
|
||||
placeholder="选择结束时间"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="单价" prop="price">
|
||||
<el-input-number
|
||||
:min="0"
|
||||
style="width: 75%"
|
||||
v-model="dataForm.price"
|
||||
clearable
|
||||
placeholder="请输入允许留存时间" />
|
||||
<el-input-number :min="0" style="width: 75%" v-model="dataForm.price" clearable placeholder="请输入单价" />
|
||||
{{ unit }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="dataForm.remark"
|
||||
clearable
|
||||
placeholder="请输入备注" />
|
||||
<el-input v-model="dataForm.remark" clearable placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -146,7 +116,7 @@ export default {
|
||||
this.dataForm.code = item.code;
|
||||
this.unit =
|
||||
'元/' +
|
||||
this.urlOptions.dictArr.dict0.find((d) => d.value === item.unit)
|
||||
this.urlOptions.dictArr.dict0.find((d) => d.value == item.unit)
|
||||
.label;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -47,15 +47,15 @@ const tableProps = [
|
||||
prop: 'equipmentName',
|
||||
label: '设备',
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: '规格',
|
||||
showOverflowtooltip: true,
|
||||
},
|
||||
{
|
||||
prop: 'process',
|
||||
label: '产品工艺',
|
||||
},
|
||||
// {
|
||||
// prop: 'size',
|
||||
// label: '规格',
|
||||
// showOverflowtooltip: true,
|
||||
// },
|
||||
// {
|
||||
// prop: 'process',
|
||||
// label: '产品工艺',
|
||||
// },
|
||||
{
|
||||
prop: 'standardCt',
|
||||
label: '标准节拍pcs/min',
|
||||
@@ -119,12 +119,12 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
// 获取数据列表
|
||||
init(lineId, startTime, endTime) {
|
||||
init(lId, startTime, endTime) {
|
||||
this.eqChartData = [];
|
||||
this.time.startTime = startTime;
|
||||
this.time.endTime = endTime;
|
||||
this.dataListLoading = true;
|
||||
getNewCTDet(lineId).then((response) => {
|
||||
getNewCTDet({ lineId: [lId], startTime, endTime }).then((response) => {
|
||||
this.tableData = response.data;
|
||||
this.dataListLoading = false;
|
||||
});
|
||||
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
|
||||
},
|
||||
{ prop: 'name', label: '设备类型名称' },
|
||||
{ prop: 'code', label: '检测类型编码' },
|
||||
{ prop: 'code', label: '设备类型编码' },
|
||||
{ prop: 'remark', label: '备注' },
|
||||
],
|
||||
searchBarFormConfig: [
|
||||
|
||||
@@ -1,70 +1,40 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
:visible.sync="visible"
|
||||
:show-close="false"
|
||||
:wrapper-closable="false"
|
||||
class="drawer"
|
||||
size="60%">
|
||||
<el-drawer :visible.sync="visible" :show-close="false" :wrapper-closable="false" class="drawer" size="60%">
|
||||
<small-title slot="title" :no-padding="true">
|
||||
{{ isdetail ? '详情' : !dataForm.id ? '新增' : '编辑' }}
|
||||
</small-title>
|
||||
|
||||
<div class="content">
|
||||
<div class="visual-part">
|
||||
<el-form
|
||||
ref="dataForm"
|
||||
:model="dataForm"
|
||||
:rules="dataRule"
|
||||
label-width="100px"
|
||||
label-position="top"
|
||||
<el-form ref="dataForm" :model="dataForm" :rules="dataRule" label-width="100px" label-position="top"
|
||||
@keyup.enter.native="dataFormSubmit">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品编码" prop="code">
|
||||
<el-input
|
||||
v-model="dataForm.code"
|
||||
clearable
|
||||
:disabled="isdetail"
|
||||
placeholder="请输入产品编码" />
|
||||
<el-input v-model="dataForm.code" clearable :disabled="isdetail" placeholder="请输入产品编码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品名称" prop="name">
|
||||
<el-input
|
||||
v-model="dataForm.name"
|
||||
clearable
|
||||
:disabled="isdetail"
|
||||
placeholder="请输入产品名称" />
|
||||
<el-input v-model="dataForm.name" clearable :disabled="isdetail" placeholder="请输入产品名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品类型" prop="typeDictValue">
|
||||
<el-select
|
||||
v-model="dataForm.typeDictValue"
|
||||
style="width: 100%"
|
||||
:disabled="isdetail"
|
||||
<el-select v-model="dataForm.typeDictValue" style="width: 100%" :disabled="isdetail"
|
||||
placeholder="请选择产品类型">
|
||||
<el-option
|
||||
v-for="dict in getDictDatas(DICT_TYPE.PRODUCT_TYPE)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
<el-option v-for="dict in getDictDatas(DICT_TYPE.PRODUCT_TYPE)" :key="dict.value" :label="dict.label"
|
||||
:value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="单位" prop="unitDictValue">
|
||||
<el-select
|
||||
v-model="dataForm.unitDictValue"
|
||||
style="width: 100%"
|
||||
:disabled="isdetail"
|
||||
<el-select v-model="dataForm.unitDictValue" style="width: 100%" :disabled="isdetail"
|
||||
placeholder="请选择单位">
|
||||
<el-option
|
||||
v-for="dict in getDictDatas(DICT_TYPE.UNIT_DICT)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
<el-option v-for="dict in getDictDatas(DICT_TYPE.UNIT_DICT)" :key="dict.value" :label="dict.label"
|
||||
:value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -73,80 +43,67 @@
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="原片规格" prop="originalSpecifications">
|
||||
<el-input
|
||||
:disabled="isdetail"
|
||||
v-model="dataForm.originalSpecifications"
|
||||
placeholder="请输入原片规格" />
|
||||
<el-input :disabled="isdetail" v-model="dataForm.originalSpecifications" placeholder="请输入原片规格" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="原片单位平方数" prop="originalArea">
|
||||
<el-input
|
||||
:disabled="isdetail"
|
||||
v-model="dataForm.originalArea"
|
||||
placeholder="请输入原片单位平方数" />
|
||||
<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-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
|
||||
:disabled="isdetail"
|
||||
v-model="dataForm.area"
|
||||
placeholder="请输入深加工单位平方数" />
|
||||
<el-input :disabled="isdetail" v-model="dataForm.area" placeholder="请输入深加工单位平方数" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="完成单位产品用时" prop="processTime">
|
||||
<el-input
|
||||
:disabled="isdetail"
|
||||
v-model="dataForm.processTime"
|
||||
placeholder="请输入完成单位产品用时" />
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完成单位产品用时(S)" prop="processTime">
|
||||
<el-input :disabled="isdetail" v-model="dataForm.processTime" placeholder="请输入完成单位产品用时(S)" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label=" 产品工艺" prop="processTypes">
|
||||
<el-select :disabled="isdetail" collapse-tags multiple v-model="dataForm.processTypes" clearable
|
||||
style="width: 100%" placeholder="请选择产品工艺">
|
||||
<el-option v-for="dict in processTypeList" :key="dict.value" :label="dict.label"
|
||||
:value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label=" 基板类型" prop="typeDictValue">
|
||||
<el-select :disabled="isdetail" v-model="dataForm.typeDictValue" clearable style="width: 100%"
|
||||
placeholder="请选择基板类型">
|
||||
<el-option v-for="dict in typeList" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<small-title
|
||||
style="margin: 16px 0; padding-left: 8px"
|
||||
:no-padding="true">
|
||||
<small-title style="margin: 16px 0; padding-left: 8px" :no-padding="true">
|
||||
产品属性列表
|
||||
</small-title>
|
||||
|
||||
<div class="attr-list">
|
||||
<base-table
|
||||
:table-props="tableProps"
|
||||
:page="listQuery.pageNo"
|
||||
:limit="listQuery.pageSize"
|
||||
:add-button-show="isdetail ? null : '添加属性'"
|
||||
@emitButtonClick="addNew()"
|
||||
:table-data="productAttributeList">
|
||||
<method-btn
|
||||
v-if="!isdetail"
|
||||
slot="handleBtn"
|
||||
:width="120"
|
||||
label="操作"
|
||||
:method-list="tableBtn"
|
||||
<base-table :table-props="tableProps" :page="listQuery.pageNo" :limit="listQuery.pageSize"
|
||||
:add-button-show="isdetail ? null : '添加属性'" @emitButtonClick="addNew()" :table-data="productAttributeList">
|
||||
<method-btn v-if="!isdetail" slot="handleBtn" :width="120" label="操作" :method-list="tableBtn"
|
||||
@clickBtn="handleClick" />
|
||||
</base-table>
|
||||
<pagination
|
||||
v-show="listQuery.total > 0"
|
||||
:total="listQuery.total"
|
||||
:page.sync="listQuery.pageNo"
|
||||
:limit.sync="listQuery.pageSize"
|
||||
:page-sizes="[5, 10, 15]"
|
||||
@pagination="getList" />
|
||||
<pagination v-show="listQuery.total > 0" :total="listQuery.total" :page.sync="listQuery.pageNo"
|
||||
:limit.sync="listQuery.pageSize" :page-sizes="[5, 10, 15]" @pagination="getList" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -177,10 +134,7 @@
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<product-attr-add
|
||||
v-if="addOrUpdateVisible"
|
||||
ref="addOrUpdate"
|
||||
:product-id="dataForm.id"
|
||||
<product-attr-add v-if="addOrUpdateVisible" ref="addOrUpdate" :product-id="dataForm.id"
|
||||
@refreshDataList="getList" />
|
||||
</el-drawer>
|
||||
</template>
|
||||
@@ -200,7 +154,7 @@ import {
|
||||
import productAttrAdd from './attr-add';
|
||||
import { parseTime } from '../../mixins/code-filter';
|
||||
import SmallTitle from './SmallTitle';
|
||||
|
||||
import { listData } from "@/api/system/dict/data"; //数据字典接口
|
||||
const tableBtn = [
|
||||
{
|
||||
type: 'edit',
|
||||
@@ -247,12 +201,32 @@ export default {
|
||||
unitDictValue: '', // 单位id
|
||||
originalSpecifications: '', // 原片规格
|
||||
originalArea: 0, // 原片单位平方数
|
||||
processTypes: [],
|
||||
typeDictValue: null,
|
||||
},
|
||||
typeList: [],
|
||||
listQuery: {
|
||||
pageSize: 10,
|
||||
pageNo: 1,
|
||||
total: 0,
|
||||
},
|
||||
processTypeList: [
|
||||
// {
|
||||
// value: '1',
|
||||
// label: '压花丝印'
|
||||
// },
|
||||
// {
|
||||
// value: '2',
|
||||
// label: '无印打孔'
|
||||
// },
|
||||
// {
|
||||
// value: '3',
|
||||
// label: '单层镀膜'
|
||||
// }, {
|
||||
// value: '4',
|
||||
// label: '双层镀膜'
|
||||
// }
|
||||
],
|
||||
dataRule: {
|
||||
code: [
|
||||
{
|
||||
@@ -307,14 +281,37 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
async initData() {
|
||||
this.productAttributeList.splice(0);
|
||||
this.listQuery.total = 0;
|
||||
const typeRes = await listData({
|
||||
pageNo:
|
||||
1,
|
||||
pageSize
|
||||
: 10,
|
||||
dictType
|
||||
: 'product_type'
|
||||
})
|
||||
|
||||
this.typeList = typeRes.data.list
|
||||
console.log('typeRes', this.typeList);
|
||||
const processTypeRes = await listData({
|
||||
pageNo:
|
||||
1,
|
||||
pageSize
|
||||
: 10,
|
||||
dictType
|
||||
: 'process_type'
|
||||
})
|
||||
|
||||
this.processTypeList = processTypeRes.data.list
|
||||
console.log('typeRes', this.typeList);
|
||||
},
|
||||
init(id, isdetail) {
|
||||
this.initData();
|
||||
this.isdetail = isdetail || false;
|
||||
this.dataForm.id = id || null;
|
||||
// this.dataForm.processTypes = [] // 清空工艺选择
|
||||
this.visible = true;
|
||||
|
||||
this.$nextTick(() => {
|
||||
@@ -322,8 +319,25 @@ export default {
|
||||
|
||||
if (this.dataForm.id) {
|
||||
// 获取产品详情
|
||||
getProduct(id).then((response) => {
|
||||
this.dataForm = response.data;
|
||||
getProduct(id).then((res) => {
|
||||
const resData = res.data || {};
|
||||
// 逐个字段赋值(保留响应式)
|
||||
this.dataForm.name = resData.name || '';
|
||||
this.dataForm.code = resData.code || '';
|
||||
this.dataForm.area = resData.area || 0;
|
||||
this.dataForm.typeDictValue = resData.typeDictValue || null;
|
||||
this.dataForm.processTime = resData.processTime || null;
|
||||
this.dataForm.specifications = resData.specifications || '';
|
||||
this.dataForm.unitDictValue = resData.unitDictValue || '';
|
||||
this.dataForm.originalSpecifications = resData.originalSpecifications || '';
|
||||
this.dataForm.originalArea = resData.originalArea || 0;
|
||||
|
||||
// 处理工艺列表:确保是数组,过滤空值
|
||||
this.dataForm.processTypes = resData.processType
|
||||
? resData.processType.split(',').filter(Boolean)
|
||||
: [];
|
||||
|
||||
console.log('工艺列表(编辑时):', this.dataForm.processTypes); // 验证是否为 ["1","2"] 格式
|
||||
});
|
||||
// 获取产品的属性列表
|
||||
this.getList();
|
||||
@@ -348,8 +362,7 @@ export default {
|
||||
handleClick(raw) {
|
||||
if (raw.type === 'delete') {
|
||||
this.$confirm(
|
||||
`确定对${
|
||||
raw.data.name
|
||||
`确定对${raw.data.name
|
||||
? '[名称=' + raw.data.name + ']'
|
||||
: '[序号=' + raw.data._pageIndex + ']'
|
||||
}进行删除操作?`,
|
||||
@@ -381,6 +394,7 @@ export default {
|
||||
dataFormSubmit() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
|
||||
// 修改的提交
|
||||
if (this.dataForm.id) {
|
||||
updateProduct(this.dataForm).then((response) => {
|
||||
@@ -449,6 +463,7 @@ export default {
|
||||
padding: 32px 32px 24px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.drawer>>>.el-drawer__body {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
@@ -469,7 +484,8 @@ export default {
|
||||
max-height: 76vh;
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
padding-right: 10px; /* 调整滚动条样式 */
|
||||
padding-right: 10px;
|
||||
/* 调整滚动条样式 */
|
||||
}
|
||||
|
||||
.drawer>>>.el-form,
|
||||
|
||||
278
src/views/core/monitoring/groupReport/baseTable.vue
Normal file
278
src/views/core/monitoring/groupReport/baseTable.vue
Normal 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> -->
|
||||
331
src/views/core/monitoring/groupReport/gr-detail.vue
Normal file
331
src/views/core/monitoring/groupReport/gr-detail.vue
Normal 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>
|
||||
594
src/views/core/monitoring/groupReport/index.vue
Normal file
594
src/views/core/monitoring/groupReport/index.vue
Normal 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>
|
||||
280
src/views/core/monitoring/lineAuto/BarChart.vue
Normal file
280
src/views/core/monitoring/lineAuto/BarChart.vue
Normal file
@@ -0,0 +1,280 @@
|
||||
<template>
|
||||
<div :class="className" :style="{ height: height, width: width, marginLeft: '10px' }" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
require('echarts/theme/macarons'); // 引入主题
|
||||
import resize from '@/utils/chartMixins/resize';
|
||||
|
||||
const animationDuration = 1000;
|
||||
|
||||
export default {
|
||||
mixins: [resize], // 混入 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, // 图表实例
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听 barData 变化(深度监听数组内部元素)
|
||||
barData: {
|
||||
deep: true,
|
||||
handler: 'handleBarDataChange', // 调用处理方法
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 组件挂载后初始化图表(确保 DOM 已就绪)
|
||||
this.$nextTick(() => {
|
||||
this.initChart();
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 组件销毁前清理图表实例
|
||||
if (this.chart) {
|
||||
this.chart.dispose();
|
||||
this.chart = null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// barData 变化时的处理方法
|
||||
handleBarDataChange() {
|
||||
// 确保 DOM 存在再更新图表
|
||||
this.$nextTick(() => {
|
||||
// 如果图表未初始化,先初始化;否则直接更新数据
|
||||
if (!this.chart) {
|
||||
this.initChart();
|
||||
} else {
|
||||
this.updateChart();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 初始化图表
|
||||
initChart() {
|
||||
// 避免重复初始化(先销毁旧实例)
|
||||
if (this.chart) {
|
||||
this.chart.dispose();
|
||||
}
|
||||
|
||||
// 确保 DOM 元素存在
|
||||
if (!this.$el) {
|
||||
console.error('图表容器 DOM 元素不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化图表实例
|
||||
this.chart = echarts.init(this.$el, 'macarons');
|
||||
// 设置图表配置
|
||||
this.setChartOption();
|
||||
},
|
||||
|
||||
// 更新图表数据(复用配置逻辑)
|
||||
updateChart() {
|
||||
if (!this.chart) return;
|
||||
this.setChartOption();
|
||||
},
|
||||
|
||||
// 图表配置项(抽离为单独方法,方便初始化和更新复用)
|
||||
setChartOption() {
|
||||
const dataValues = this.barData.flatMap(item => [item.inputNum || 0, item.outputNum || 0]);
|
||||
const maxData = Math.max(...dataValues, 0); // 加 0 确保无数据时 maxData 为 0
|
||||
|
||||
// 2. 计算 Y 轴最大值(留 10% 余量,避免数据顶到顶部)
|
||||
let yMax = 0;
|
||||
if (maxData > 0) {
|
||||
yMax = Math.ceil(maxData * 1.1); // 向上取整,确保刻度为整数
|
||||
} else {
|
||||
yMax = 100; // 无数据时默认最大值为 100,避免 Y 轴消失
|
||||
}
|
||||
|
||||
// 3. 计算 interval(5 个刻度对应 4 个间隔,向上取整确保间隔为整数)
|
||||
const yInterval = Math.ceil((yMax - 0) / 4); // min 固定为 0,直接减 0
|
||||
|
||||
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: {
|
||||
left: 20,
|
||||
right: 30,
|
||||
top:40,
|
||||
bottom: 10,
|
||||
|
||||
containLabel: true,
|
||||
splitArea: {
|
||||
show: false // 关键:关闭网格背景分区(去掉间隔色块)
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: this.barData.map((item) => item.lineName),
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
width: 1 // 轴线宽度(可选,默认 1,可按需调整)
|
||||
}
|
||||
},
|
||||
// 2. 控制 X 轴刻度线颜色(与轴线颜色保持一致,视觉统一)
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)', // 刻度线颜色,需与轴线颜色匹配
|
||||
width: 1 // 刻度线宽度(可选)
|
||||
},
|
||||
alignWithLabel: true // 可选:让刻度线与文字对齐(避免文字偏移时刻度线错位)
|
||||
},
|
||||
// 3. 控制 X 轴文字颜色(如:深灰色 rgba(0, 0, 0, 0.45))
|
||||
axisLabel: {
|
||||
color: 'rgba(0, 0, 0, 0.45)6', // 文字颜色,可自定义
|
||||
fontSize: 12, // 可选:调整文字大小(默认 12,按需修改)
|
||||
// 可选:文字过长时换行/省略(避免文字重叠,按需开启)
|
||||
formatter: (value) => {
|
||||
// 示例:文字超过 6 个字符时换行(可根据需求调整字符数)
|
||||
if (value.length > 6) {
|
||||
return value.slice(0, 6) + '\n' + value.slice(6);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
// 原有配置(若需保留可解开注释)
|
||||
// axisPointer: {
|
||||
// type: 'shadow',
|
||||
// }
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '投入/产出 片',
|
||||
min: 0, // 最小值固定为 0
|
||||
max: yMax,
|
||||
interval: yInterval,
|
||||
splitArea: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
formatter: '{value}',
|
||||
color: 'rgba(0, 0, 0, 0.45)'
|
||||
},
|
||||
|
||||
// 可选:修改 Y 轴名称颜色(与文字颜色保持一致)
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '加工成品率',
|
||||
min: 0,
|
||||
max: 100, // 成品率固定 0-100%
|
||||
interval: 25, // 100 / 4 = 25,刚好 5 个刻度(0、25、50、75、100)
|
||||
axisLabel: {
|
||||
formatter: '{value} %',
|
||||
color: 'rgba(0, 0, 0, 0.45)'
|
||||
},
|
||||
splitArea: {
|
||||
show: false
|
||||
},
|
||||
// 可选:修改 Y 轴名称颜色
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)'
|
||||
}
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '投入',
|
||||
type: 'bar',
|
||||
barWidth: '20',
|
||||
data: this.barData.map((item) => item.inputNum),
|
||||
tooltip: {
|
||||
valueFormatter: (value) => `${value} 片`,
|
||||
},
|
||||
animationDuration,
|
||||
},
|
||||
{
|
||||
name: '产出',
|
||||
type: 'bar',
|
||||
barWidth: '20',
|
||||
data: this.barData.map((item) => item.outputNum),
|
||||
tooltip: {
|
||||
valueFormatter: (value) => `${value} 片`,
|
||||
},
|
||||
animationDuration,
|
||||
},
|
||||
{
|
||||
name: '加工成品率',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
tooltip: {
|
||||
valueFormatter: (value) => `${value} %`,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
distance: 6,
|
||||
fontSize: 11,
|
||||
color: '#333333',
|
||||
formatter: (params) => `${params.value}` // 显示单位
|
||||
},
|
||||
data: this.barData.map((item) => item.processingRatio),
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
350
src/views/core/monitoring/nextClip/hisData.vue
Normal file
350
src/views/core/monitoring/nextClip/hisData.vue
Normal file
@@ -0,0 +1,350 @@
|
||||
<!--
|
||||
* @Author: Do not edit
|
||||
* @Date: 2023-08-29 14:59:29
|
||||
* @LastEditTime: 2024-12-02 13:44:47
|
||||
* @LastEditors: zwq
|
||||
* @Description:
|
||||
-->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- :isFold="true" 控制展开 -->
|
||||
<search-bar
|
||||
:formConfigs="formConfig"
|
||||
ref="searchBarForm"
|
||||
@headBtnClick="buttonClick" />
|
||||
<base-table
|
||||
v-if="showData.length"
|
||||
class="right-aside"
|
||||
v-loading="dataListLoading"
|
||||
:table-props="tableProps"
|
||||
:page="listQuery.pageNo"
|
||||
:limit="listQuery.pageSize"
|
||||
:table-data="showData"
|
||||
>
|
||||
<!-- <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 { parseTime } from '../../mixins/code-filter';
|
||||
import { getDownLogHisData, getPdList, getThick } from '@/api/core/monitoring/index'
|
||||
import * as XLSX from 'xlsx'
|
||||
import FileSaver from 'file-saver'
|
||||
import jsPDF from 'jspdf'
|
||||
import html2canvas from 'html2canvas'
|
||||
|
||||
const tableProps = [
|
||||
{
|
||||
prop: 'productionLineName',
|
||||
label: '产线'
|
||||
},
|
||||
{
|
||||
prop: 'eqName',
|
||||
label: '下片机械手编号'
|
||||
},
|
||||
{
|
||||
prop: 'pos',
|
||||
label: '工位编号'
|
||||
},
|
||||
{
|
||||
prop: 'pallet',
|
||||
label: '托数/托'
|
||||
},
|
||||
{
|
||||
prop: 'palletNum',
|
||||
label: '一托玻璃数量/片'
|
||||
},
|
||||
{
|
||||
prop: 'startTime',
|
||||
label: '开始时间',
|
||||
filter: parseTime,
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'endTime',
|
||||
label: '结束时间',
|
||||
filter: parseTime,
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'length',
|
||||
label: '玻璃长度/mm'
|
||||
},
|
||||
{
|
||||
prop: 'width',
|
||||
label: '玻璃宽度/mm',
|
||||
},
|
||||
{
|
||||
prop: 'thick',
|
||||
label: '玻璃长度/mm'
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
urlOptions: {
|
||||
getDataListURL: getDownLogHisData
|
||||
},
|
||||
tableData: [],
|
||||
listQuery: {
|
||||
pageSize: 10,
|
||||
pageNo: 1,
|
||||
total: 1,
|
||||
eqName: undefined,
|
||||
productionLineId: undefined,
|
||||
thick:undefined
|
||||
},
|
||||
exportLoading: false,
|
||||
dataListLoading: false,
|
||||
selectedList: [],
|
||||
dialogVisible: false,
|
||||
addOrEditTitle: '',
|
||||
addOrUpdateVisible: false,
|
||||
tableProps,
|
||||
tableBtn: [
|
||||
{
|
||||
type: 'his',
|
||||
btnName: '历史',
|
||||
},
|
||||
].filter((v) => v),
|
||||
tableData: [],
|
||||
showData: [],
|
||||
fileName: '',
|
||||
formConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
param: 'productionLineId'
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '玻璃型号',
|
||||
selectOptions: [],
|
||||
param: 'thick'
|
||||
},
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '统计开始时间',
|
||||
dateType: 'daterange',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: "yyyy-MM-dd HH:mm:ss",
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
defaultSelect: []
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
{
|
||||
type: 'separate',
|
||||
},
|
||||
{
|
||||
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
|
||||
type: 'button',
|
||||
btnName: '导出',
|
||||
name: 'export',
|
||||
color: 'warning',
|
||||
}
|
||||
],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.searchBarForm.formInline.productionLineId = this.$route.query.productionLineId
|
||||
this.$refs.searchBarForm.formInline.thick = this.$route.query.thick
|
||||
this.listQuery.productionLineId = this.$route.query.productionLineId
|
||||
this.listQuery.thick = this.$route.query.thick
|
||||
this.getDataList()
|
||||
this.getPdLineList()
|
||||
console.log('this.$route.query', this.$route.query);
|
||||
|
||||
},
|
||||
methods: {
|
||||
handleClick(val) {
|
||||
this.addOrUpdateVisible = true;
|
||||
this.addOrEditTitle =
|
||||
val.data?.factoryName + '-' + val.data?.lineName + ' 详情';
|
||||
this.$nextTick(() => {
|
||||
this.$refs.eqDetail.init(
|
||||
val.data.lineId,
|
||||
this.listQuery.startTime,
|
||||
this.listQuery.endTime
|
||||
);
|
||||
});
|
||||
},
|
||||
exportXlsx() {
|
||||
if (!this.showData.length) {
|
||||
this.$message.warning('暂无数据可导出');
|
||||
return;
|
||||
}
|
||||
|
||||
this.exportLoading = true;
|
||||
|
||||
try {
|
||||
// 1. 处理导出数据(格式化时间字段)
|
||||
const exportData = this.showData.map(item => {
|
||||
const formatItem = { ...item };
|
||||
// 格式化时间字段
|
||||
if (formatItem.startTime) formatItem.startTime = parseTime(formatItem.startTime);
|
||||
if (formatItem.endTime) formatItem.endTime = parseTime(formatItem.endTime);
|
||||
return formatItem;
|
||||
});
|
||||
|
||||
// 2. 构建表头映射:{ prop: label },只保留表格配置中存在的列
|
||||
const headerMap = {};
|
||||
this.tableProps.forEach(col => {
|
||||
if (col.prop && col.label) {
|
||||
headerMap[col.prop] = col.label;
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 转换数据:将prop键名替换为label,按tableProps顺序排列列
|
||||
const formattedData = exportData.map(item => {
|
||||
const newItem = {};
|
||||
// 按表格配置顺序遍历列,确保Excel列顺序与表格一致
|
||||
this.tableProps.forEach(col => {
|
||||
const prop = col.prop;
|
||||
const label = col.label;
|
||||
if (prop && label) {
|
||||
// 处理可能的undefined值,避免导出为空字符串
|
||||
newItem[label] = item[prop] ?? '';
|
||||
}
|
||||
});
|
||||
return newItem;
|
||||
});
|
||||
|
||||
// 4. 创建工作表(使用处理后的带label表头的数据)
|
||||
const worksheet = XLSX.utils.json_to_sheet(formattedData);
|
||||
|
||||
// 5. 创建工作簿并添加工作表
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '下片日志数据');
|
||||
|
||||
// 6. 生成Excel文件
|
||||
const excelBuffer = XLSX.write(workbook, {
|
||||
bookType: 'xlsx',
|
||||
type: 'array'
|
||||
});
|
||||
|
||||
// 7. 保存文件
|
||||
const blob = new Blob([excelBuffer], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
|
||||
});
|
||||
|
||||
// 8. 生成文件名(包含查询条件信息)
|
||||
let fileName = '下片历史';
|
||||
if (this.listQuery.productionLineId) {
|
||||
const lineItem = this.formConfig[0].selectOptions.find(
|
||||
item => item.id === this.listQuery.productionLineId
|
||||
);
|
||||
if (lineItem) fileName += lineItem.name + '_';
|
||||
}
|
||||
if (this.listQuery.thick) {
|
||||
fileName += this.listQuery.thick + '_';
|
||||
}
|
||||
// 添加时间戳避免文件名重复
|
||||
fileName += + '.xlsx';
|
||||
|
||||
FileSaver.saveAs(blob, fileName);
|
||||
this.$message.success('导出成功');
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error);
|
||||
this.$message.error('导出失败,请重试');
|
||||
} finally {
|
||||
this.exportLoading = false;
|
||||
}
|
||||
},
|
||||
getPdLineList() {
|
||||
getPdList().then((res) => {
|
||||
this.formConfig[0].selectOptions = res.data || []
|
||||
})
|
||||
getThick().then((res) => {
|
||||
this.formConfig[1].selectOptions = res.data.map((item) => {
|
||||
return {
|
||||
id: item.thick + 'mm',
|
||||
name: item.thick + 'mm'
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
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.productionLineId = val.productionLineId ? val.productionLineId : undefined;
|
||||
this.listQuery.thick = val.thick ? val.thick : undefined;
|
||||
this.listQuery.startTime = val.timeVal ? val.timeVal[0] : undefined;
|
||||
this.listQuery.endTime = val.timeVal ? val.timeVal[1] : undefined;
|
||||
|
||||
//this.listQuery.reportEndTime = val.timeVal ? [new Date(val.timeVal[1]).getTime()] : undefined;
|
||||
this.getDataList();
|
||||
break;
|
||||
case 'export':
|
||||
this.exportXlsx();
|
||||
break;
|
||||
default:
|
||||
console.log(val);
|
||||
}
|
||||
},
|
||||
// 获取数据列表
|
||||
getDataList() {
|
||||
this.listQuery.eqName = this.$route.query.eqName
|
||||
this.dataListLoading = true;
|
||||
this.urlOptions.getDataListURL(this.listQuery).then(response => {
|
||||
this.tableData = response.data.list
|
||||
this.showData = this.tableData
|
||||
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();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
373
src/views/core/monitoring/nextClip/index.vue
Normal file
373
src/views/core/monitoring/nextClip/index.vue
Normal file
@@ -0,0 +1,373 @@
|
||||
<!--
|
||||
* @Author: Do not edit
|
||||
* @Date: 2023-08-29 14:59:29
|
||||
* @LastEditTime: 2024-12-02 13:44:47
|
||||
* @LastEditors: zwq
|
||||
* @Description:
|
||||
-->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- :isFold="true" 控制展开 -->
|
||||
<search-bar
|
||||
:formConfigs="formConfig"
|
||||
ref="searchBarForm"
|
||||
@headBtnClick="buttonClick" />
|
||||
<base-table
|
||||
v-if="showData.length"
|
||||
class="right-aside"
|
||||
v-loading="dataListLoading"
|
||||
:table-props="tableProps"
|
||||
:page="listQuery.pageNo"
|
||||
:limit="listQuery.pageSize"
|
||||
:table-data="showData"
|
||||
>
|
||||
<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 { parseTime } from '../../mixins/code-filter';
|
||||
import { getDownLogPage, getPdList, getThick, exportDownLogData } from '@/api/core/monitoring/index'
|
||||
import * as XLSX from 'xlsx'
|
||||
import FileSaver from 'file-saver'
|
||||
import jsPDF from 'jspdf'
|
||||
import html2canvas from 'html2canvas'
|
||||
|
||||
const tableProps = [
|
||||
{
|
||||
prop: 'productionLineName',
|
||||
label: '产线'
|
||||
},
|
||||
{
|
||||
prop: 'eqName',
|
||||
label: '下片机械手编号'
|
||||
},
|
||||
{
|
||||
prop: 'pos',
|
||||
label: '工位编号'
|
||||
},
|
||||
{
|
||||
prop: 'pallet',
|
||||
label: '托数/托'
|
||||
},
|
||||
{
|
||||
prop: 'palletNum',
|
||||
label: '一托玻璃数量/片'
|
||||
},
|
||||
{
|
||||
prop: 'startTime',
|
||||
label: '开始时间',
|
||||
filter: parseTime,
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'endTime',
|
||||
label: '结束时间',
|
||||
filter: parseTime,
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'length',
|
||||
label: '玻璃长度/mm'
|
||||
},
|
||||
{
|
||||
prop: 'width',
|
||||
label: '玻璃宽度/mm',
|
||||
},
|
||||
{
|
||||
prop: 'thick',
|
||||
label: '玻璃厚度/mm'
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
urlOptions: {
|
||||
getDataListURL: getDownLogPage
|
||||
},
|
||||
tableData: [],
|
||||
listQuery: {
|
||||
pageSize: 10,
|
||||
pageNo: 1,
|
||||
total: 1,
|
||||
productionLineId: undefined,
|
||||
thick: undefined,
|
||||
|
||||
},
|
||||
exportLoading: false,
|
||||
dataListLoading: false,
|
||||
selectedList: [],
|
||||
dialogVisible: false,
|
||||
addOrEditTitle: '',
|
||||
addOrUpdateVisible: false,
|
||||
tableProps,
|
||||
tableBtn: [
|
||||
{
|
||||
type: 'his',
|
||||
btnName: '历史',
|
||||
},
|
||||
].filter((v) => v),
|
||||
tableData: [],
|
||||
showData: [],
|
||||
fileName: '',
|
||||
formConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
param: 'productionLineId'
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '玻璃型号',
|
||||
selectOptions: [],
|
||||
param: 'thick'
|
||||
},
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '统计开始时间',
|
||||
dateType: 'daterange',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: "yyyy-MM-dd HH:mm:ss",
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
defaultSelect: []
|
||||
},
|
||||
{
|
||||
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() {
|
||||
this.getDataList()
|
||||
this.getPdLineList()
|
||||
},
|
||||
methods: {
|
||||
handleClick(val) {
|
||||
console.log(val);
|
||||
if (val.type === 'his') {
|
||||
this.$router.push({
|
||||
path: 'nextClipHis',
|
||||
query: {
|
||||
eqName: val.data.eqName,
|
||||
productionLineId: this.listQuery.productionLineId,
|
||||
thick: this.listQuery.thick,
|
||||
},
|
||||
});
|
||||
}
|
||||
// this.addOrUpdateVisible = true;
|
||||
// this.addOrEditTitle =
|
||||
// val.data?.factoryName + '-' + val.data?.lineName + ' 详情';
|
||||
// this.$nextTick(() => {
|
||||
// this.$refs.eqDetail.init(
|
||||
// val.data.lineId,
|
||||
// this.listQuery.startTime,
|
||||
// this.listQuery.endTime
|
||||
// );
|
||||
// });
|
||||
},
|
||||
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 || []
|
||||
})
|
||||
getThick().then((res) => {
|
||||
this.formConfig[1].selectOptions = res.data.map((item) => {
|
||||
return {
|
||||
id: item.thick + 'mm',
|
||||
name: item.thick + 'mm'
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
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.productionLineId = val.productionLineId ? val.productionLineId : undefined;
|
||||
this.listQuery.thick = val.thick ? val.thick : undefined;
|
||||
this.listQuery.startTime = val.timeVal ? val.timeVal[0]: undefined;
|
||||
this.listQuery.endTime = val.timeVal ? val.timeVal[1]: undefined;
|
||||
|
||||
//this.listQuery.reportEndTime = val.timeVal ? [new Date(val.timeVal[1]).getTime()] : undefined;
|
||||
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.list
|
||||
this.showData = this.tableData
|
||||
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();
|
||||
},
|
||||
handleExport() {
|
||||
// 处理查询参数
|
||||
let params = { ...this.listQuery };
|
||||
params.pageNo = undefined;
|
||||
params.pageSize = undefined;
|
||||
this.$modal.confirm('是否确认导出下片日志?').then(() => {
|
||||
this.exportLoading = true;
|
||||
return exportDownLogData(params);
|
||||
}).then(response => {
|
||||
this.$download.excel(response, '下片日志.xls');
|
||||
this.exportLoading = false;
|
||||
}).catch(() => { });
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
280
src/views/core/monitoring/productAuto/BarChart.vue
Normal file
280
src/views/core/monitoring/productAuto/BarChart.vue
Normal file
@@ -0,0 +1,280 @@
|
||||
<template>
|
||||
<div :class="className" :style="{ height: height, width: width, marginLeft: '10px' }" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
require('echarts/theme/macarons'); // 引入主题
|
||||
import resize from '@/utils/chartMixins/resize';
|
||||
|
||||
const animationDuration = 1000;
|
||||
|
||||
export default {
|
||||
mixins: [resize], // 混入 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, // 图表实例
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听 barData 变化(深度监听数组内部元素)
|
||||
barData: {
|
||||
deep: true,
|
||||
handler: 'handleBarDataChange', // 调用处理方法
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 组件挂载后初始化图表(确保 DOM 已就绪)
|
||||
this.$nextTick(() => {
|
||||
this.initChart();
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 组件销毁前清理图表实例
|
||||
if (this.chart) {
|
||||
this.chart.dispose();
|
||||
this.chart = null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// barData 变化时的处理方法
|
||||
handleBarDataChange() {
|
||||
// 确保 DOM 存在再更新图表
|
||||
this.$nextTick(() => {
|
||||
// 如果图表未初始化,先初始化;否则直接更新数据
|
||||
if (!this.chart) {
|
||||
this.initChart();
|
||||
} else {
|
||||
this.updateChart();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 初始化图表
|
||||
initChart() {
|
||||
// 避免重复初始化(先销毁旧实例)
|
||||
if (this.chart) {
|
||||
this.chart.dispose();
|
||||
}
|
||||
|
||||
// 确保 DOM 元素存在
|
||||
if (!this.$el) {
|
||||
console.error('图表容器 DOM 元素不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化图表实例
|
||||
this.chart = echarts.init(this.$el, 'macarons');
|
||||
// 设置图表配置
|
||||
this.setChartOption();
|
||||
},
|
||||
|
||||
// 更新图表数据(复用配置逻辑)
|
||||
updateChart() {
|
||||
if (!this.chart) return;
|
||||
this.setChartOption();
|
||||
},
|
||||
|
||||
// 图表配置项(抽离为单独方法,方便初始化和更新复用)
|
||||
setChartOption() {
|
||||
const dataValues = this.barData.flatMap(item => [item.inputNum || 0, item.outputNum || 0]);
|
||||
const maxData = Math.max(...dataValues, 0); // 加 0 确保无数据时 maxData 为 0
|
||||
|
||||
// 2. 计算 Y 轴最大值(留 10% 余量,避免数据顶到顶部)
|
||||
let yMax = 0;
|
||||
if (maxData > 0) {
|
||||
yMax = Math.ceil(maxData * 1.1); // 向上取整,确保刻度为整数
|
||||
} else {
|
||||
yMax = 100; // 无数据时默认最大值为 100,避免 Y 轴消失
|
||||
}
|
||||
|
||||
// 3. 计算 interval(5 个刻度对应 4 个间隔,向上取整确保间隔为整数)
|
||||
const yInterval = Math.ceil((yMax - 0) / 4); // min 固定为 0,直接减 0
|
||||
|
||||
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: {
|
||||
left: 20,
|
||||
right: 30,
|
||||
top:40,
|
||||
bottom: 10,
|
||||
|
||||
containLabel: true,
|
||||
splitArea: {
|
||||
show: false // 关键:关闭网格背景分区(去掉间隔色块)
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: this.barData.map((item) => item.lineName),
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)',
|
||||
width: 1 // 轴线宽度(可选,默认 1,可按需调整)
|
||||
}
|
||||
},
|
||||
// 2. 控制 X 轴刻度线颜色(与轴线颜色保持一致,视觉统一)
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)', // 刻度线颜色,需与轴线颜色匹配
|
||||
width: 1 // 刻度线宽度(可选)
|
||||
},
|
||||
alignWithLabel: true // 可选:让刻度线与文字对齐(避免文字偏移时刻度线错位)
|
||||
},
|
||||
// 3. 控制 X 轴文字颜色(如:深灰色 rgba(0, 0, 0, 0.45))
|
||||
axisLabel: {
|
||||
color: 'rgba(0, 0, 0, 0.45)6', // 文字颜色,可自定义
|
||||
fontSize: 12, // 可选:调整文字大小(默认 12,按需修改)
|
||||
// 可选:文字过长时换行/省略(避免文字重叠,按需开启)
|
||||
formatter: (value) => {
|
||||
// 示例:文字超过 6 个字符时换行(可根据需求调整字符数)
|
||||
if (value.length > 6) {
|
||||
return value.slice(0, 6) + '\n' + value.slice(6);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
// 原有配置(若需保留可解开注释)
|
||||
// axisPointer: {
|
||||
// type: 'shadow',
|
||||
// }
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '投入/产出 片',
|
||||
min: 0, // 最小值固定为 0
|
||||
max: yMax,
|
||||
interval: yInterval,
|
||||
splitArea: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
formatter: '{value}',
|
||||
color: 'rgba(0, 0, 0, 0.45)'
|
||||
},
|
||||
|
||||
// 可选:修改 Y 轴名称颜色(与文字颜色保持一致)
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '加工成品率',
|
||||
min: 0,
|
||||
max: 100, // 成品率固定 0-100%
|
||||
interval: 25, // 100 / 4 = 25,刚好 5 个刻度(0、25、50、75、100)
|
||||
axisLabel: {
|
||||
formatter: '{value} %',
|
||||
color: 'rgba(0, 0, 0, 0.45)'
|
||||
},
|
||||
splitArea: {
|
||||
show: false
|
||||
},
|
||||
// 可选:修改 Y 轴名称颜色
|
||||
nameTextStyle: {
|
||||
color: 'rgba(0, 0, 0, 0.45)'
|
||||
}
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '投入',
|
||||
type: 'bar',
|
||||
barWidth: '20',
|
||||
data: this.barData.map((item) => item.inputNum),
|
||||
tooltip: {
|
||||
valueFormatter: (value) => `${value} 片`,
|
||||
},
|
||||
animationDuration,
|
||||
},
|
||||
{
|
||||
name: '产出',
|
||||
type: 'bar',
|
||||
barWidth: '20',
|
||||
data: this.barData.map((item) => item.outputNum),
|
||||
tooltip: {
|
||||
valueFormatter: (value) => `${value} 片`,
|
||||
},
|
||||
animationDuration,
|
||||
},
|
||||
{
|
||||
name: '加工成品率',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
tooltip: {
|
||||
valueFormatter: (value) => `${value} %`,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
distance: 6,
|
||||
fontSize: 11,
|
||||
color: '#333333',
|
||||
formatter: (params) => `${params.value}` // 显示单位
|
||||
},
|
||||
data: this.barData.map((item) => item.processingRatio),
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
273
src/views/core/monitoring/productAuto/baseTable.vue
Normal file
273
src/views/core/monitoring/productAuto/baseTable.vue
Normal 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>
|
||||
File diff suppressed because it is too large
Load Diff
65
src/views/core/monitoring/rawFilmReport/SmallTitle.vue
Normal file
65
src/views/core/monitoring/rawFilmReport/SmallTitle.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<!--
|
||||
* @Author: zwq
|
||||
* @Date: 2023-08-01 15:27:31
|
||||
* @LastEditors: zwq
|
||||
* @LastEditTime: 2023-08-01 16:25:54
|
||||
* @Description:
|
||||
-->
|
||||
<template>
|
||||
<div :class="[className, { 'p-0': noPadding }]">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
size: {
|
||||
// 取值范围: xl lg md sm
|
||||
type: String,
|
||||
default: 'de',
|
||||
validator: function (val) {
|
||||
return ['xl', 'lg', 'de', 'md', 'sm'].indexOf(val) !== -1;
|
||||
},
|
||||
},
|
||||
noPadding: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
className: function () {
|
||||
return `${this.size}-title`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$pxls: (xl, 28px) (lg, 24px) (de, 20px) (md, 18px) (sm, 16px);
|
||||
$mgr: 8px;
|
||||
@each $size, $height in $pxls {
|
||||
.#{$size}-title {
|
||||
font-size: 18px;
|
||||
line-height: $height;
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
font-family: '微软雅黑', 'Microsoft YaHei', Arial, Helvetica, sans-serif;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 4px;
|
||||
height: $height + 2px;
|
||||
border-radius: 1px;
|
||||
margin-right: $mgr;
|
||||
background-color: #0b58ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.p-0 {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
221
src/views/core/monitoring/rawFilmReport/add-or-updata.vue
Normal file
221
src/views/core/monitoring/rawFilmReport/add-or-updata.vue
Normal file
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<el-dialog :visible.sync="visible" width="40%">
|
||||
<small-title slot="title" :no-padding="true">
|
||||
{{ !dataForm.id ? '新增' : '编辑' }}
|
||||
</small-title>
|
||||
|
||||
<div class="content">
|
||||
<div class="visual-part">
|
||||
<el-form ref="dataForm" :model="dataForm" :rules="dataRule" label-width="100px"
|
||||
@keyup.enter.native="dataFormSubmit">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="维度" prop="statisticType">
|
||||
<el-select v-model="dataForm.statisticType" style="width: 100%" placeholder="请选择维度">
|
||||
<el-option v-for="item in statisticTypeList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="厚度" prop="modifyThick">
|
||||
<el-input v-model="dataForm.modifyThick" placeholder="请输入厚度" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="在线速度" prop="modifySpeed">
|
||||
<el-input v-model="dataForm.modifySpeed" placeholder="请输入在线速度" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="宽度" prop="modifyWidth">
|
||||
<el-input v-model="dataForm.modifyWidth" placeholder="请输入宽度" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="拉引量" prop="modifyInArea">
|
||||
<el-input v-model="dataForm.modifyInArea" placeholder="请输入拉引量" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="下片面积" prop="modifyOutArea">
|
||||
<el-input v-model="dataForm.modifyOutArea" placeholder="请输入下片面积" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="良品率" prop="modifyRatio">
|
||||
<el-input v-model="dataForm.modifyRatio" placeholder="请输入良品率" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button style="" @click="goback()">取消</el-button>
|
||||
<el-button type="primary" @click="dataFormSubmit()">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { editCostOriginRadioHisData } from '@/api/core/monitoring/index'
|
||||
import { parseTime } from '../../mixins/code-filter';
|
||||
import SmallTitle from './SmallTitle';
|
||||
export default {
|
||||
components: { SmallTitle },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
addOrUpdateVisible: false,
|
||||
statisticTypeList: [
|
||||
{
|
||||
id: '0',
|
||||
name: '班组'
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
name: '日'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '周'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: '月'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: '年'
|
||||
}
|
||||
],
|
||||
dataForm: {
|
||||
id: null,
|
||||
statisticType:undefined,
|
||||
modifyThick: undefined,
|
||||
modifySpeed: undefined,
|
||||
modifyWidth: undefined,
|
||||
modifyInArea: undefined,
|
||||
modifyOutArea: undefined,
|
||||
modifyRatio: undefined,
|
||||
},
|
||||
dataRule: {
|
||||
statisticType: [
|
||||
{
|
||||
required: true,
|
||||
message: '维度不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
// {
|
||||
// type: 'number',
|
||||
// message: '产品编码为数字类型',
|
||||
// trigger: 'blur',
|
||||
// transfom: 'val => Number(val)',
|
||||
// },
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init(data) {
|
||||
console.log(data,'data');
|
||||
|
||||
this.dataForm.id = data.id || null;
|
||||
this.visible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].resetFields();
|
||||
this.dataForm = {
|
||||
id: data.id || null,
|
||||
statisticType: data.statisticType || undefined,
|
||||
modifyThick: data.thick || undefined, // 厚度对应
|
||||
modifySpeed: data.speed || undefined, // 在线速度对应
|
||||
modifyWidth: data.width || undefined, // 掰边宽度对应
|
||||
modifyInArea: data.inArea || undefined, // 拉引量对应
|
||||
modifyOutArea: data.outArea || undefined, // 下片面积对应
|
||||
modifyRatio: data.ratio || undefined, // 良品率对应
|
||||
};
|
||||
});
|
||||
},
|
||||
// 表单提交
|
||||
dataFormSubmit() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
// 修改的提交
|
||||
if (this.dataForm.id) {
|
||||
editCostOriginRadioHisData(this.dataForm).then((response) => {
|
||||
this.$modal.msgSuccess('修改成功');
|
||||
this.visible = false;
|
||||
this.$emit('refreshDataList');
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
goback() {
|
||||
this.$emit('refreshDataList');
|
||||
this.visible = false;
|
||||
this.initData();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.drawer >>> .el-drawer {
|
||||
border-radius: 8px 0 0 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer >>> .el-form-item__label {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.drawer >>> .el-drawer__header {
|
||||
margin: 0;
|
||||
padding: 32px 32px 24px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
.drawer >>> .el-drawer__body {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer >>> .content {
|
||||
padding: 30px 24px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* height: 100%; */
|
||||
}
|
||||
|
||||
.drawer >>> .visual-part {
|
||||
flex: 1 auto;
|
||||
max-height: 76vh;
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
padding-right: 10px; /* 调整滚动条样式 */
|
||||
}
|
||||
|
||||
.drawer >>> .el-form,
|
||||
.drawer >>> .attr-list {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.drawer-body__footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 18px;
|
||||
}
|
||||
</style>
|
||||
536
src/views/core/monitoring/rawFilmReport/index.vue
Normal file
536
src/views/core/monitoring/rawFilmReport/index.vue
Normal file
@@ -0,0 +1,536 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- :isFold="true" 控制展开 -->
|
||||
<search-bar :formConfigs="formConfig" ref="searchBarForm" @headBtnClick="buttonClick"
|
||||
@select-changed="selectType" />
|
||||
<base-table v-if="tableData.length" class="right-aside" 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>
|
||||
<div v-else class="no-data-bg"></div>
|
||||
<pagination :limit.sync="listQuery.pageSize" :page.sync="listQuery.pageNo" :total="listQuery.total"
|
||||
@pagination="getDataList" />
|
||||
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import AddOrUpdate from './add-or-updata';
|
||||
|
||||
import { parseTime } from '../../mixins/code-filter';
|
||||
import { getCostOriginRadioHisData, getPdList } from '@/api/core/monitoring/index';
|
||||
import { exportCostOriginRadioHisData } from '../../../../api/core/monitoring';
|
||||
|
||||
// Vue2 中注册全局方法(如果需要)
|
||||
Vue.prototype.$download = Vue.prototype.$download || {
|
||||
excel: (response, fileName) => {
|
||||
const blob = new Blob([response.data], { type: 'application/vnd.ms-excel' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const aLink = document.createElement('a');
|
||||
aLink.style.display = 'none';
|
||||
aLink.href = url;
|
||||
aLink.setAttribute('download', fileName);
|
||||
document.body.appendChild(aLink);
|
||||
aLink.click();
|
||||
document.body.removeChild(aLink);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}
|
||||
};
|
||||
|
||||
Vue.prototype.$modal = Vue.prototype.$modal || {
|
||||
confirm: (message) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.confirm(message)) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const tableProps = [
|
||||
{
|
||||
prop: 'reportType',
|
||||
label: '报表类型'
|
||||
},
|
||||
{
|
||||
prop: 'time',
|
||||
label: '日期',
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'bindObjectName',
|
||||
label: '产线'
|
||||
},
|
||||
{
|
||||
prop: 'thick',
|
||||
label: '厚度'
|
||||
},
|
||||
{
|
||||
prop: 'speed',
|
||||
label: '在线速度'
|
||||
},
|
||||
{
|
||||
prop: 'width',
|
||||
label: '掰边宽度'
|
||||
},
|
||||
{
|
||||
prop: 'inArea',
|
||||
label: '拉引量/㎡'
|
||||
},
|
||||
{
|
||||
prop: 'outArea',
|
||||
label: '下片面积/㎡'
|
||||
},
|
||||
{
|
||||
prop: 'ratio',
|
||||
label: '良品率/%'
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 工具函数:获取选择时间所在周的起始和结束时间(Vue2 兼容)
|
||||
* @param {String|Date} selectTime - 选择的时间(支持格式:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss 或 Date 对象)
|
||||
* @returns {Array} [startDate, endDate] - 所在周周一 00:00:00 至 周日 23:59:59(Date 对象)
|
||||
*/
|
||||
function getSelectedWeekRange(selectTime) {
|
||||
// 兼容 String 类型时间和 Date 对象,统一转为 Date 实例
|
||||
const targetDate = new Date(selectTime);
|
||||
// 处理无效日期(若传入非法时间,返回当前时间的本周范围)
|
||||
// if (isNaN(targetDate.getTime())) {
|
||||
// console.warn('传入的时间格式无效,将使用当前时间计算本周范围');
|
||||
// return getCurrentWeekRange(); // 可根据需求改为抛出错误或返回空
|
||||
// }
|
||||
|
||||
const day = targetDate.getDay() || 7; // 周日为 7(避免周日 -0 天仍为周日)
|
||||
const start = new Date(targetDate);
|
||||
start.setDate(targetDate.getDate() - day + 1); // 计算所在周的周一
|
||||
start.setHours(0, 0, 0, 0); // 重置时分秒为 00:00:00.000
|
||||
|
||||
const end = new Date(start);
|
||||
end.setDate(start.getDate() + 6); // 周一 +6 天 = 周日
|
||||
end.setHours(23, 59, 59, 999); // 重置时分秒为 23:59:59.999
|
||||
|
||||
return [start, end];
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具函数:获取选择时间所在年的起始和结束时间(Vue2 兼容)
|
||||
* @param {String|Date} selectTime - 选择的时间(支持格式:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss 或 Date 对象)
|
||||
* @returns {Array} [startDate, endDate] - 所在年 1月1日 00:00:00 至 12月31日 23:59:59(Date 对象)
|
||||
*/
|
||||
function getSelectedYearRange(selectTime) {
|
||||
// 兼容 String 类型时间和 Date 对象,统一转为 Date 实例
|
||||
const targetDate = new Date(selectTime);
|
||||
// 处理无效日期(若传入非法时间,返回当前时间的本年范围)
|
||||
// if (isNaN(targetDate.getTime())) {
|
||||
// console.warn('传入的时间格式无效,将使用当前时间计算本年范围');
|
||||
// return getCurrentYearRange(); // 可根据需求改为抛出错误或返回空
|
||||
// }
|
||||
|
||||
const year = targetDate.getFullYear(); // 获取选择时间的年份
|
||||
const start = new Date(year, 0, 1); // 所在年 1月1日(月份从 0 开始)
|
||||
start.setHours(0, 0, 0, 0); // 重置时分秒为 00:00:00.000
|
||||
|
||||
const end = new Date(year, 11, 31); // 所在年 12月31日(11 代表 12 月)
|
||||
end.setHours(23, 59, 59, 999); // 重置时分秒为 23:59:59.999
|
||||
|
||||
return [start, end];
|
||||
}
|
||||
|
||||
// 格式化时间为 yyyy-MM-dd HH:mm:ss(Vue2 兼容)
|
||||
function formatDateTime(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AddOrUpdate
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
urlOptions: {
|
||||
getDataListURL: getCostOriginRadioHisData
|
||||
},
|
||||
tableData: [],
|
||||
listQuery: {
|
||||
pageSize: 10,
|
||||
pageNo: 1,
|
||||
total: 1,
|
||||
bindObjectId: undefined,
|
||||
statisticType: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined
|
||||
},
|
||||
pdLineList: [],
|
||||
exportLoading: false,
|
||||
dataListLoading: false,
|
||||
selectedList: [],
|
||||
dialogVisible: false,
|
||||
addOrEditTitle: '',
|
||||
addOrUpdateVisible: false,
|
||||
tableProps,
|
||||
tableBtn: [
|
||||
{
|
||||
type: 'edit',
|
||||
btnName: '编辑',
|
||||
},
|
||||
].filter(v => v),
|
||||
fileName: '',
|
||||
formConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '报表类型',
|
||||
onchange: true,
|
||||
selectOptions: [
|
||||
{ id: '0', name: '班组' },
|
||||
{ id: '1', name: '日' },
|
||||
{ id: '2', name: '周' },
|
||||
{ id: '3', name: '月' },
|
||||
{ id: '4', name: '年' }
|
||||
],
|
||||
param: 'statisticType',
|
||||
index: 1,
|
||||
extraOptions: [
|
||||
{
|
||||
parent: 'statisticType',
|
||||
type: 'datePicker',
|
||||
label: '统计时间',
|
||||
dateType: 'daterange',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
defaultSelect: [],
|
||||
width: 250,
|
||||
key: 'datePicker-0', // 唯一 key,触发重新渲染
|
||||
appendToBody: true // 优化定位:挂载到 body 下
|
||||
},
|
||||
// 日 - 日期范围选择
|
||||
{
|
||||
parent: 'statisticType',
|
||||
type: 'datePicker',
|
||||
label: '统计时间',
|
||||
dateType: 'daterange',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeValDay',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
defaultSelect: [],
|
||||
width: 250,
|
||||
key: 'datePicker-1', // 唯一 key,触发重新渲染
|
||||
appendToBody: true // 优化定位:挂载到 body 下
|
||||
},
|
||||
// 周 - 单个日期选择(自动获取本周范围)
|
||||
{
|
||||
parent: 'statisticType',
|
||||
type: 'datePicker',
|
||||
label: '统计时间',
|
||||
dateType: 'week',
|
||||
placeholder: '选择日期',
|
||||
format: 'yyyy 第 WW 周',
|
||||
pickerOptions: {
|
||||
firstDayOfWeek: 1 // 数字1表示周一作为周的第一天(0=周日,1=周一,依此类推)
|
||||
},
|
||||
valueFormat: 'yyyy-MM-dd',
|
||||
param: 'timeValWeek',
|
||||
width: 250,
|
||||
key: 'datePicker-2', // 唯一 key,触发重新渲染
|
||||
appendToBody: true // 优化定位:挂载到 body 下
|
||||
},
|
||||
// 月 - 日期范围选择
|
||||
{
|
||||
parent: 'statisticType',
|
||||
type: 'datePicker',
|
||||
label: '统计时间',
|
||||
dateType: 'monthrange',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeValMonth',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
width: 250,
|
||||
key: 'datePicker-3', // 唯一 key,触发重新渲染
|
||||
appendToBody: true // 优化定位:挂载到 body 下
|
||||
},
|
||||
// 年 - 单个日期选择(自动获取本年范围)
|
||||
{
|
||||
parent: 'statisticType',
|
||||
type: 'datePicker',
|
||||
label: '统计时间',
|
||||
dateType: 'year',
|
||||
placeholder: '选择年份',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'yyyy-MM-dd',
|
||||
param: 'timeValYear',
|
||||
width: 250,
|
||||
key: 'datePicker-4', // 唯一 key,触发重新渲染
|
||||
appendToBody: true // 优化定位:挂载到 body 下
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
param: 'bindObjectId'
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
{
|
||||
type: 'separate',
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '导出',
|
||||
name: 'export',
|
||||
color: 'warning',
|
||||
}
|
||||
],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听报表类型变化,强制刷新日期选择器
|
||||
'listQuery.statisticType'(newVal, oldVal) {
|
||||
if (newVal !== oldVal && this.$refs.searchBarForm) {
|
||||
// 触发 search-bar 组件重新渲染(如果 search-bar 支持)
|
||||
if (this.$refs.searchBarForm.$forceUpdate) {
|
||||
this.$refs.searchBarForm.$forceUpdate();
|
||||
}
|
||||
// 延迟重置定位,确保 DOM 已更新
|
||||
setTimeout(() => {
|
||||
const datePickerEl = this.$refs.searchBarForm.$el.querySelector('.el-date-picker');
|
||||
if (datePickerEl) {
|
||||
// 触发 Element UI 日期选择器重新计算定位(内部方法)
|
||||
const datePickerInstance = datePickerEl.__vue__;
|
||||
if (datePickerInstance && datePickerInstance.updatePopper) {
|
||||
datePickerInstance.updatePopper();
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// Vue2 中 $refs 需在 $nextTick 中访问(确保 DOM 渲染完成)
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.searchBarForm) {
|
||||
this.$refs.searchBarForm.formInline.statisticType = '1';
|
||||
}
|
||||
});
|
||||
this.listQuery.statisticType = '1';
|
||||
this.getDataList();
|
||||
this.getPdLineList();
|
||||
},
|
||||
methods: {
|
||||
selectType(val) {
|
||||
// 报表类型切换时的回调(如需扩展可在此添加逻辑)
|
||||
console.log('报表类型切换:', val);
|
||||
},
|
||||
handleClick(val) {
|
||||
console.log('操作按钮点击:', val);
|
||||
if (val.type === 'edit') {
|
||||
this.addOrUpdateVisible = true;
|
||||
// Vue2 中 $nextTick 确保子组件已渲染
|
||||
this.$nextTick(() => {
|
||||
this.$refs.addOrUpdate.init(val.data);
|
||||
});
|
||||
}
|
||||
},
|
||||
getPdLineList() {
|
||||
getPdList().then(res => {
|
||||
// Vue2 中数组赋值需确保响应式
|
||||
this.$set(this.formConfig[1], 'selectOptions', res.data || []);
|
||||
this.pdLineList = res.data || [];
|
||||
}).catch(err => {
|
||||
console.error('获取产线列表失败:', err);
|
||||
});
|
||||
},
|
||||
selectChange(val) {
|
||||
console.log('选择变更:', val);
|
||||
this.selectedList = val;
|
||||
},
|
||||
buttonClick(val) {
|
||||
console.log('头部按钮点击:', val);
|
||||
switch (val.btnName) {
|
||||
case 'search':
|
||||
this.listQuery.pageNo = 1;
|
||||
this.listQuery.pageSize = 10;
|
||||
this.listQuery.bindObjectId = val.bindObjectId ? val.bindObjectId : undefined;
|
||||
this.listQuery.statisticType = val.statisticType ? val.statisticType : undefined;
|
||||
|
||||
// 处理不同时间维度的时间范围
|
||||
this.handleTimeRange(val);
|
||||
|
||||
this.getDataList();
|
||||
break;
|
||||
case 'export':
|
||||
this.handleExport();
|
||||
break;
|
||||
default:
|
||||
console.log('未知按钮:', val);
|
||||
}
|
||||
},
|
||||
// 处理不同时间维度的时间范围
|
||||
handleTimeRange(val) {
|
||||
const statisticType = val.statisticType;
|
||||
const timeVal = val.timeVal;
|
||||
|
||||
const timeValDay = val.timeValDay;
|
||||
|
||||
const timeValWeek = val.timeValWeek;
|
||||
const timeValMonth = val.timeValMonth;
|
||||
const timeValYear = val.timeValYear;
|
||||
|
||||
|
||||
// 重置时间参数
|
||||
this.listQuery.startTime = undefined;
|
||||
this.listQuery.endTime = undefined;
|
||||
|
||||
switch (statisticType) {
|
||||
case '0': // 班组 - 沿用原时间范围
|
||||
if (timeVal && timeVal.length === 2) {
|
||||
this.listQuery.startTime = timeVal[0];
|
||||
this.listQuery.endTime = timeVal[1];
|
||||
}
|
||||
break;
|
||||
case '1': // 日 - 沿用原时间范围
|
||||
if (timeValDay && timeValDay.length === 2) {
|
||||
this.listQuery.startTime = timeValDay[0];
|
||||
this.listQuery.endTime = timeValDay[1];
|
||||
}
|
||||
break;
|
||||
case '3': // 月 - 沿用原时间范围
|
||||
if (timeValMonth && timeValMonth.length === 2) {
|
||||
this.listQuery.startTime = timeValMonth[0];
|
||||
this.listQuery.endTime = timeValMonth[1];
|
||||
}
|
||||
break;
|
||||
case '2': // 周 - 自动计算本周范围
|
||||
if (timeValWeek) {
|
||||
const [start, end] = getSelectedWeekRange(timeValWeek);
|
||||
this.listQuery.startTime = formatDateTime(start);
|
||||
this.listQuery.endTime = formatDateTime(end);
|
||||
}
|
||||
break;
|
||||
case '4': // 年 - 自动计算本年范围
|
||||
if (timeValYear) {
|
||||
const [start, end] = getSelectedYearRange(timeValYear);
|
||||
this.listQuery.startTime = formatDateTime(start);
|
||||
this.listQuery.endTime = formatDateTime(end);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 获取数据列表
|
||||
getDataList() {
|
||||
this.dataListLoading = true;
|
||||
this.urlOptions.getDataListURL(this.listQuery)
|
||||
.then(response => {
|
||||
const arr = ['班组', '日', '周', '月', '年'];
|
||||
// Vue2 中数组赋值确保响应式
|
||||
this.tableData = (response.data?.list || []).map(item => {
|
||||
item.reportType = arr[this.listQuery.statisticType] || '';
|
||||
item.statisticType = this.listQuery.statisticType;
|
||||
|
||||
// 匹配产线名称
|
||||
// const targetLine = this.pdLineList.find(line => line.id === item.bindObjectId);
|
||||
// item.bindObjectName = targetLine ? targetLine.name : ''
|
||||
return item;
|
||||
})
|
||||
this.listQuery.total = response.data?.total || 0;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('获取数据失败:', err);
|
||||
this.tableData = [];
|
||||
this.listQuery.total = 0;
|
||||
})
|
||||
.finally(() => {
|
||||
this.dataListLoading = false;
|
||||
});
|
||||
},
|
||||
// 每页数变更
|
||||
sizeChangeHandle(val) {
|
||||
this.listQuery.pageSize = val;
|
||||
this.listQuery.pageNo = 1;
|
||||
this.getDataList();
|
||||
},
|
||||
// 当前页变更
|
||||
currentChangeHandle(val) {
|
||||
this.listQuery.pageNo = val;
|
||||
this.getDataList();
|
||||
},
|
||||
// 导出处理
|
||||
handleExport() {
|
||||
const params = { ...this.listQuery };
|
||||
// 移除分页参数
|
||||
delete params.pageNo;
|
||||
delete params.pageSize;
|
||||
delete params.total;
|
||||
|
||||
this.$modal.confirm('是否确认导出原片报表?')
|
||||
.then(() => {
|
||||
this.exportLoading = true;
|
||||
return exportCostOriginRadioHisData(params);
|
||||
})
|
||||
.then(response => {
|
||||
this.$download.excel(response, '原片报表.xls');
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('导出失败:', err);
|
||||
})
|
||||
.finally(() => {
|
||||
this.exportLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
// Vue2 中监听数据变化(如需)
|
||||
watch: {
|
||||
'listQuery.statisticType'(newVal) {
|
||||
console.log('报表类型变更:', newVal);
|
||||
// 可添加类型变更后的额外逻辑
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.no-data-bg {
|
||||
height: 400px;
|
||||
background-color: #f5f7fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.right-aside {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
274
src/views/core/monitoring/rawFilmReport/searchBar.vue
Normal file
274
src/views/core/monitoring/rawFilmReport/searchBar.vue
Normal file
@@ -0,0 +1,274 @@
|
||||
<template>
|
||||
<div class="searchBarBox divHeight" ref="searchBarRef" :style="{ paddingRight: isFold ? '55px' : '0px' }">
|
||||
<el-form :inline="true" ref="searchBarForm" :model="formInline" class="searchBar">
|
||||
<span class="blue-block" v-if="removeBlue ? false : true"></span>
|
||||
<template v-for="item in formConfig">
|
||||
<el-form-item v-if="item.type !== ''" :key="item.param" :label="item.label ? item.label : ''"
|
||||
:required="item.required ? item.required : false">
|
||||
<el-input v-if="item.type === 'input'" v-model="formInline[item.param]"
|
||||
:size="item.size ? item.size : 'small'" clearable :disabled="item.disabled ? item.disabled : false"
|
||||
:style="item.width ? 'width:' + item.width + 'px' : 'width:200px'"
|
||||
:placeholder="item.placeholder ? item.placeholder : ''" />
|
||||
<el-select v-if="item.type === 'select'" v-model="formInline[item.param]"
|
||||
:size="item.size ? item.size : 'small'" :filterable="item.filterable ? item.filterable : false"
|
||||
:multiple="item.multiple ? item.multiple : false" :clearable="item.clearable === false ? false : true"
|
||||
:style="item.width ? 'width:' + item.width + 'px' : 'width:200px'" :placeholder="item.label" @change="
|
||||
item.onchange
|
||||
? $emit('select-changed', {
|
||||
param: item.param,
|
||||
value: formInline[item.param]
|
||||
})
|
||||
: null
|
||||
">
|
||||
<el-option v-for="(sub, i) in item.selectOptions" :key="i"
|
||||
:label="item.labelField ? sub[item.labelField] : sub['name']"
|
||||
:value="item.valueField ? sub[item.valueField] : sub['id']" />
|
||||
</el-select>
|
||||
<el-date-picker v-if="item.type === 'datePicker'" :key="item.param" :size="item.size ? item.size : 'small'"
|
||||
v-model="formInline[item.param]" :type="item.dateType" :format="item.format ? item.format : 'yyyy-MM-dd'"
|
||||
:value-format="item.valueFormat ? item.valueFormat : null" :default-time="item.defaultTime || null"
|
||||
:range-separator="item.rangeSeparator || null" :start-placeholder="item.startPlaceholder || null"
|
||||
:end-placeholder="item.endPlaceholder || null" :placeholder="item.placeholder"
|
||||
:picker-options="item.pickerOptions ? item.pickerOptions : null"
|
||||
:clearable="item.clearable === false ? false : true"
|
||||
:style="item.width ? 'width:' + item.width + 'px' : (item.dateType === 'datetimerange' ? 'width:340px' : (item.dateType === 'daterange' ? 'width:220px' : 'width:140px'))" />
|
||||
<el-autocomplete v-if="item.type === 'autocomplete'" v-model="formInline[item.param]"
|
||||
:value-key="item.valueKey ? item.valueKey : 'value'" :size="item.size ? item.size : 'small'"
|
||||
:fetch-suggestions="item.querySearch" :placeholder="item.placeholder"
|
||||
:clearable="item.clearable === false ? false : true"
|
||||
:style="item.width ? 'width:' + item.width + 'px' : 'width:200px'" filterable />
|
||||
<el-cascader v-if="item.type === 'cascader'" v-model="formInline[item.param]" :options="item.selectOptions"
|
||||
:props="item.cascaderProps" :size="item.size ? item.size : 'small'"
|
||||
:clearable="item.clearable === false ? false : true"
|
||||
:show-all-levels="item.showAllLevels === false ? false : true"
|
||||
:collapse-tags="item.collapseTags === true ? true : false"
|
||||
:style="item.width ? 'width:' + item.width + 'px' : 'width:200px'" @change="
|
||||
item.onChange
|
||||
? $emit('cascader-change', {
|
||||
param: item.param,
|
||||
value: formInline[item.param]
|
||||
})
|
||||
: null
|
||||
"></el-cascader>
|
||||
<el-button v-if="item.type === 'button'" :type="item.color" :size="item.size ? item.size : 'small'"
|
||||
:plain="item.plain ? item.plain : false" :round="item.round ? item.round : false"
|
||||
@click="headBtnClick(item.name)">{{ item.btnName }}</el-button>
|
||||
<span v-if="item.type === 'separate'" class="separateStyle"></span>
|
||||
<!-- 可用于显示其他按钮 -->
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item>
|
||||
<slot></slot>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span v-if="isFold" class="foldClass" @click='switchMode'>
|
||||
{{ isExpand ? '收起' : '展开' }}
|
||||
<i class="iconfont" :class="isExpand ? 'icon-upward' : 'icon-downward'"></i>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'SearchBar',
|
||||
props: {
|
||||
formConfigs: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
removeBlue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isFold: {// 多行模式(默认否)
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const formInline = {}
|
||||
const formConfig = this.formConfigs
|
||||
let hasExtraOptions = false
|
||||
for (const obj of formConfig) {
|
||||
if (obj.type !== 'button') {
|
||||
if (obj.defaultSelect === false || obj.defaultSelect === 0) {
|
||||
formInline[obj.param] = obj.defaultSelect
|
||||
} else {
|
||||
formInline[obj.param] = obj.defaultSelect || '' // defaultSelect下拉框默认选中项
|
||||
}
|
||||
}
|
||||
if (obj.extraOptions) {
|
||||
hasExtraOptions = true
|
||||
}
|
||||
}
|
||||
return {
|
||||
formInline,
|
||||
formConfig,
|
||||
hasExtraOptions,
|
||||
isExpand: false // 是否展开(默认否)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
formConfig: {
|
||||
handler() {
|
||||
for (const obj of this.formConfig) {
|
||||
if (obj.defaultSelect) {
|
||||
this.formInline[obj.param] = obj.defaultSelect
|
||||
} else if (obj.defaultSelect === null) {
|
||||
// 需要手动从外部清除选项缓存的情况,确保在外部配置项中可直接设置null
|
||||
this.formInline[obj.param] = ''
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
},
|
||||
formInline: {
|
||||
handler: function () {
|
||||
this.$forceUpdate()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
if (this.hasExtraOptions) {
|
||||
// 如果有额外参数就处理,如果没有就算了
|
||||
for (const obj of this.formConfig) {
|
||||
if (obj.extraOptions) {
|
||||
// 注: 对obj.extraOptions的选择是互斥的!
|
||||
this.$watch(
|
||||
`formInline.${obj.param}`,
|
||||
function (newVal) {
|
||||
let deleteCount = 0
|
||||
if (obj.index + 1 < this.formConfig.length) {
|
||||
// 如果obj不是最后一个配置
|
||||
const nextConfig = this.formConfig[obj.index + 1]
|
||||
if (nextConfig.parent && nextConfig.parent === obj.param)
|
||||
deleteCount = 1
|
||||
}
|
||||
const currentConfig = Object.assign(
|
||||
{},
|
||||
obj.extraOptions[newVal]
|
||||
)
|
||||
this.formConfig.splice(
|
||||
obj.index + 1,
|
||||
deleteCount,
|
||||
currentConfig
|
||||
)
|
||||
// 修改 formInline
|
||||
this.$set(this.formInline, currentConfig.param, '')
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headBtnClick(btnName) {
|
||||
this.formInline.btnName = btnName
|
||||
this.$emit('headBtnClick', this.formInline)
|
||||
},
|
||||
resetForm() {
|
||||
this.$refs.searchBarForm.resetFields()
|
||||
const formInline = {}
|
||||
const formConfig = this.formConfigs
|
||||
for (const obj of formConfig) {
|
||||
if (obj.type !== 'button') {
|
||||
if (obj.defaultSelect === false || obj.defaultSelect === 0) {
|
||||
formInline[obj.param] = obj.defaultSelect
|
||||
} else {
|
||||
formInline[obj.param] = obj.defaultSelect || '' // defaultSelect下拉框默认选中项
|
||||
}
|
||||
}
|
||||
}
|
||||
this.formInline = formInline
|
||||
},
|
||||
switchMode() {// 展开和收起切换
|
||||
this.isExpand = !this.isExpand
|
||||
const element = this.$refs.searchBarRef
|
||||
if (this.isExpand) {
|
||||
element.classList.remove('divHeight')
|
||||
} else {
|
||||
element.classList.add('divHeight')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.searchBarBox {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.searchBarBox::after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.divHeight {
|
||||
height: 45px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.searchBar .blue-block {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #0B58FF;
|
||||
border-radius: 1px;
|
||||
margin-right: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.searchBar .el-form-item {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.searchBar .el-date-editor .el-range__icon {
|
||||
font-size: 16px;
|
||||
color: #0B58FF;
|
||||
}
|
||||
|
||||
.searchBar .el-input__prefix .el-icon-date {
|
||||
font-size: 16px;
|
||||
color: #0B58FF;
|
||||
}
|
||||
|
||||
.searchBar .el-input__prefix .el-icon-time {
|
||||
font-size: 16px;
|
||||
color: #0B58FF;
|
||||
}
|
||||
|
||||
.searchBar .separateStyle {
|
||||
display: inline-block;
|
||||
width: 1px;
|
||||
height: 24px;
|
||||
background: #E8E8E8;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.searchBarBox .foldClass {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: #0B58FF;
|
||||
}
|
||||
|
||||
.searchBarBox .foldClass .iconfont {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
65
src/views/equipment/equipmentOverview/SmallTitle.vue
Normal file
65
src/views/equipment/equipmentOverview/SmallTitle.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<!--
|
||||
* @Author: zwq
|
||||
* @Date: 2023-08-01 15:27:31
|
||||
* @LastEditors: zwq
|
||||
* @LastEditTime: 2023-08-01 16:25:54
|
||||
* @Description:
|
||||
-->
|
||||
<template>
|
||||
<div :class="[className, { 'p-0': noPadding }]">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
size: {
|
||||
// 取值范围: xl lg md sm
|
||||
type: String,
|
||||
default: 'de',
|
||||
validator: function (val) {
|
||||
return ['xl', 'lg', 'de', 'md', 'sm'].indexOf(val) !== -1;
|
||||
},
|
||||
},
|
||||
noPadding: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
className: function () {
|
||||
return `${this.size}-title`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$pxls: (xl, 28px) (lg, 24px) (de, 20px) (md, 18px) (sm, 16px);
|
||||
$mgr: 8px;
|
||||
@each $size, $height in $pxls {
|
||||
.#{$size}-title {
|
||||
font-size: 18px;
|
||||
line-height: $height;
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
font-family: '微软雅黑', 'Microsoft YaHei', Arial, Helvetica, sans-serif;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 4px;
|
||||
height: $height + 2px;
|
||||
border-radius: 1px;
|
||||
margin-right: $mgr;
|
||||
background-color: #0b58ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.p-0 {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
134
src/views/equipment/equipmentOverview/add-or-updata.vue
Normal file
134
src/views/equipment/equipmentOverview/add-or-updata.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<el-dialog :visible.sync="visible" width="40%">
|
||||
<small-title slot="title" :no-padding="true">
|
||||
{{ this.dataForm.lineId + '·' + this.dataForm.equipmentName }}
|
||||
</small-title>
|
||||
|
||||
<div class="content">
|
||||
<div class="visual-part">
|
||||
<base-table :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>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div slot="footer" class="dialog-footer">
|
||||
<el-button style="" @click="goback()">取消</el-button>
|
||||
<el-button type="primary" @click="dataFormSubmit()">
|
||||
确定
|
||||
</el-button>
|
||||
</div> -->
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const tableProps = [
|
||||
|
||||
{
|
||||
prop: 'paramName',
|
||||
label: '参数名称'
|
||||
},
|
||||
{
|
||||
prop: 'paramValue',
|
||||
label: '当前值',
|
||||
// filter: parseTime,
|
||||
// width: 160
|
||||
},
|
||||
];
|
||||
|
||||
import { getParamMonitor } from '@/api/base/equipment';
|
||||
// import { parseTime } from '../../mixins/code-filter';
|
||||
import SmallTitle from './SmallTitle';
|
||||
export default {
|
||||
components: { SmallTitle },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
tableProps,
|
||||
tableData:[],
|
||||
listQuery: {
|
||||
pageNo: 1,
|
||||
pageSize:100,
|
||||
},
|
||||
addOrUpdateVisible: false,
|
||||
dataForm: {
|
||||
equipmentId:undefined,
|
||||
equipmentName: undefined,
|
||||
lineId: undefined,
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init(data) {
|
||||
console.log(data.paramMonitors,'data');
|
||||
|
||||
this.dataForm.equipmentId = data.equipmentId || '';
|
||||
this.dataForm.equipmentName = data.equipmentName || '';
|
||||
this.dataForm.lineId = data.lineId || '';
|
||||
|
||||
|
||||
this.visible = true;
|
||||
this.$nextTick(() => {
|
||||
// this.$refs['dataForm'].resetFields();
|
||||
// getParamMonitor({
|
||||
// equipmentId:this.dataForm.equipmentId
|
||||
// }).then((res) => {
|
||||
this.tableData = data.paramMonitors
|
||||
// })
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.drawer >>> .el-drawer {
|
||||
border-radius: 8px 0 0 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer >>> .el-form-item__label {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.drawer >>> .el-drawer__header {
|
||||
margin: 0;
|
||||
padding: 32px 32px 24px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
.drawer >>> .el-drawer__body {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer >>> .content {
|
||||
padding: 30px 24px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* height: 100%; */
|
||||
}
|
||||
|
||||
.drawer >>> .visual-part {
|
||||
flex: 1 auto;
|
||||
max-height: 76vh;
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
padding-right: 10px; /* 调整滚动条样式 */
|
||||
}
|
||||
|
||||
.drawer >>> .el-form,
|
||||
.drawer >>> .attr-list {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.drawer-body__footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 18px;
|
||||
}
|
||||
</style>
|
||||
563
src/views/equipment/equipmentOverview/alarm-or-updata.vue
Normal file
563
src/views/equipment/equipmentOverview/alarm-or-updata.vue
Normal file
@@ -0,0 +1,563 @@
|
||||
<template>
|
||||
<el-dialog :visible.sync="visible" width="80%" @close="handleClose" title-class="dialog-title">
|
||||
<small-title slot="title" :no-padding="true">
|
||||
{{ dataForm.lineId + '·' + dataForm.equipmentName }}
|
||||
</small-title>
|
||||
<search-bar removeBlue :formConfigs="formConfig" ref="searchBarForm" @headBtnClick="buttonClick" />
|
||||
<el-tabs class="custom-tabs" v-model="activeLabel" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'\u3000报警时长\u3000'" name="duration"></el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000报警次数\u3000'" name="times"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="content">
|
||||
<div class="visual-part">
|
||||
<div v-if="hasData" style="display: flex; justify-content: space-around; gap: 20px; padding: 10px 0;">
|
||||
<!-- 移除 v-if,始终渲染两个图表容器 -->
|
||||
<div id="barChart" style="width: 48%; height: 400px;"></div>
|
||||
<div id="pieChart" style="width: 48%; height: 400px;"></div>
|
||||
</div>
|
||||
<div v-if="!hasData" class="no-data">
|
||||
<el-empty description="暂无相关报警数据"></el-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAlarmDet } from '@/api/base/equipment';
|
||||
import * as echarts from 'echarts';
|
||||
import SmallTitle from './SmallTitle';
|
||||
|
||||
const CHART_CONFIG = {
|
||||
barColor: '#288AFF',
|
||||
pieColors: [
|
||||
'#288AFF', '#4096FF', '#69B1FF', '#91CFFF', '#B8E0FF',
|
||||
'#E0F2FF', '#1890FF', '#096DD9', '#0050B3', '#003A8C'
|
||||
],
|
||||
fontColor: '#333',
|
||||
lightFontColor: '#666',
|
||||
borderRadius: 4
|
||||
};
|
||||
|
||||
export default {
|
||||
components: { SmallTitle },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
hasData: false,
|
||||
listQuery: {
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
equipmentId: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined
|
||||
},
|
||||
formConfig: [
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '时间段',
|
||||
dateType: 'daterange',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'timestamp',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
defaultSelect: []
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary'
|
||||
}
|
||||
],
|
||||
activeLabel: 'duration', // 默认选中「报警时长」
|
||||
dataForm: {
|
||||
equipmentId: undefined,
|
||||
equipmentName: undefined,
|
||||
lineId: undefined
|
||||
},
|
||||
chartInstances: {
|
||||
bar: null,
|
||||
pie: null
|
||||
},
|
||||
isDomReady: false,
|
||||
originData: null // 存储原始数据
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.isDomReady = true;
|
||||
if (this.listQuery.equipmentId) {
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
// Tab 切换时自动刷新图表(无需额外操作,依赖 handleTabClick 触发查询)
|
||||
activeLabel() {
|
||||
if (this.isDomReady && this.originData) {
|
||||
this.$nextTick(() => {
|
||||
this.renderBothCharts(); // 切换 Tab 后重新渲染两个图表
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initDefaultDate() {
|
||||
const today = new Date();
|
||||
const start = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0).getTime();
|
||||
const end = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59, 0).getTime();
|
||||
|
||||
this.formConfig[0].defaultSelect = [start, end];
|
||||
this.listQuery.startTime = start;
|
||||
this.listQuery.endTime = end;
|
||||
|
||||
// 修复点1:增加多层判断,确保对象存在后再赋值
|
||||
if (this.$refs.searchBarForm && this.$refs.searchBarForm.form) {
|
||||
this.$refs.searchBarForm.form.timeVal = [start, end];
|
||||
}
|
||||
},
|
||||
|
||||
handleTabClick() {
|
||||
// 切换 Tab 时重新查询数据(或直接复用已有数据渲染)
|
||||
this.getDataList();
|
||||
},
|
||||
|
||||
buttonClick(val) {
|
||||
switch (val.btnName) {
|
||||
case 'search':
|
||||
this.listQuery.startTime = val.timeVal?.[0];
|
||||
this.listQuery.endTime = val.timeVal?.[1];
|
||||
this.getDataList();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
},
|
||||
|
||||
async getDataList() {
|
||||
try {
|
||||
if (!this.listQuery.equipmentId) {
|
||||
console.warn('设备ID不能为空');
|
||||
this.hasData = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const queryParams = {
|
||||
equipmentId: this.listQuery.equipmentId,
|
||||
startTime: this.listQuery.startTime,
|
||||
endTime: this.listQuery.endTime,
|
||||
};
|
||||
|
||||
const res = await getAlarmDet(queryParams);
|
||||
const originData = res.data || [];
|
||||
this.originData = originData;
|
||||
this.hasData = originData.length > 0;
|
||||
|
||||
if (this.hasData && this.isDomReady) {
|
||||
this.$nextTick(() => {
|
||||
this.renderBothCharts(); // 数据查询成功后,同时渲染两个图表
|
||||
});
|
||||
} else {
|
||||
this.destroyAllCharts();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取报警数据失败:', error);
|
||||
this.hasData = false;
|
||||
this.destroyAllCharts();
|
||||
}
|
||||
},
|
||||
|
||||
// 核心方法:同时渲染柱状图和饼图(根据当前 Tab 类型)
|
||||
renderBothCharts() {
|
||||
if (this.activeLabel === 'duration') {
|
||||
// 报警时长:柱状图(时长排序)+ 饼图(时长占比)
|
||||
this.renderBarChart('duration');
|
||||
this.renderPieChart('duration');
|
||||
} else {
|
||||
// 报警次数:柱状图(次数排序)+ 饼图(次数占比)
|
||||
this.renderBarChart('times');
|
||||
this.renderPieChart('times');
|
||||
}
|
||||
},
|
||||
|
||||
// 渲染柱状图(支持两种数据类型)
|
||||
renderBarChart(type) {
|
||||
this.destroyChart('bar');
|
||||
const chartDom = document.getElementById('barChart');
|
||||
if (!chartDom || !this.originData.length) return;
|
||||
|
||||
// 根据类型排序和提取数据
|
||||
let sortedData, xData, seriesData, yAxisName;
|
||||
if (type === 'duration') {
|
||||
// 报警时长:按时长降序
|
||||
sortedData = [...this.originData].sort((a, b) => b.alarmDuration - a.alarmDuration);
|
||||
seriesData = sortedData.map(item => item.alarmDuration);
|
||||
yAxisName = '报警时长';
|
||||
} else {
|
||||
// 报警次数:按次数降序
|
||||
sortedData = [...this.originData].sort((a, b) => b.alarmCount - a.alarmCount);
|
||||
seriesData = sortedData.map(item => item.alarmCount);
|
||||
yAxisName = '报警次数';
|
||||
}
|
||||
|
||||
xData = sortedData.map(item => this.truncateText(item.alarmContent, 8));
|
||||
|
||||
try {
|
||||
this.chartInstances.bar = echarts.init(chartDom);
|
||||
const option = {
|
||||
title: {
|
||||
text: `${yAxisName}统计(柱状图)`,
|
||||
left: 'center',
|
||||
textStyle: { fontSize: 14, color: CHART_CONFIG.fontColor }
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' },
|
||||
padding: 10,
|
||||
textStyle: { fontSize: 11 },
|
||||
formatter: (params) => {
|
||||
const index = params[0].dataIndex;
|
||||
const item = sortedData[index];
|
||||
return `
|
||||
<div style="text-align: left;">
|
||||
<div>${item.alarmContent}</div>
|
||||
<div>${yAxisName}:${type === 'duration' ? item.alarmDuration : item.alarmCount}</div>
|
||||
<div>占比:${type === 'duration' ? item.alarmDurationRatio.toFixed(2) : item.alarmCountRatio.toFixed(2)}%</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '5%',
|
||||
right: '5%',
|
||||
bottom: '18%',
|
||||
top: '15%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xData,
|
||||
axisTick: { alignWithLabel: true },
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
fontSize: 12,
|
||||
color: CHART_CONFIG.lightFontColor
|
||||
},
|
||||
axisLine: { lineStyle: { color: '#e8e8e8' } }
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: yAxisName,
|
||||
nameTextStyle: { fontSize: 11, color: CHART_CONFIG.lightFontColor },
|
||||
axisLabel: {
|
||||
fontSize: 11,
|
||||
color: CHART_CONFIG.lightFontColor,
|
||||
},
|
||||
axisLine: { lineStyle: { color: '#e8e8e8' } },
|
||||
splitLine: { lineStyle: { color: '#f5f5f5' } },
|
||||
max: (value) => value.max * 1.2
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: yAxisName,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: CHART_CONFIG.barColor,
|
||||
borderRadius: [CHART_CONFIG.borderRadius, CHART_CONFIG.borderRadius, 0, 0],
|
||||
shadowBlur: 3,
|
||||
shadowColor: 'rgba(40, 138, 255, 0.2)',
|
||||
shadowOffsetY: 2
|
||||
},
|
||||
barWidth: '16',
|
||||
data: seriesData,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
distance: 6,
|
||||
fontSize: 11,
|
||||
color: CHART_CONFIG.fontColor,
|
||||
formatter: (params) => `${params.value}`
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
this.chartInstances.bar.setOption(option);
|
||||
this.addResizeListener('bar');
|
||||
} catch (error) {
|
||||
console.error(`${yAxisName}柱状图初始化失败:`, error);
|
||||
setTimeout(() => this.renderBarChart(type), 200);
|
||||
}
|
||||
},
|
||||
|
||||
// 渲染饼图(支持两种数据类型)
|
||||
renderPieChart(type) {
|
||||
this.destroyChart('pie');
|
||||
const chartDom = document.getElementById('pieChart');
|
||||
if (!chartDom || !this.originData.length) return;
|
||||
|
||||
// 根据类型处理饼图数据
|
||||
let pieData, seriesName;
|
||||
if (type === 'duration') {
|
||||
// 报警时长:按时长占比处理
|
||||
seriesName = '报警时长';
|
||||
pieData = this.handlePieData(this.originData, 'alarmDuration', 'alarmDurationRatio');
|
||||
} else {
|
||||
// 报警次数:按次数占比处理
|
||||
seriesName = '报警次数';
|
||||
pieData = this.handlePieData(this.originData, 'alarmCount', 'alarmCountRatio');
|
||||
}
|
||||
|
||||
try {
|
||||
this.chartInstances.pie = echarts.init(chartDom);
|
||||
const option = {
|
||||
title: {
|
||||
text: `${seriesName}统计(饼图)`,
|
||||
left: 'center',
|
||||
textStyle: { fontSize: 14, color: CHART_CONFIG.fontColor }
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
padding: 10,
|
||||
textStyle: { fontSize: 11 },
|
||||
formatter: (params) => {
|
||||
return `
|
||||
<div style="text-align: left;">
|
||||
<div>${params.name}</div>
|
||||
<div>${seriesName}:${params.value}${type === 'duration' ? '' : '次'}</div>
|
||||
<div>占比:${params.percent.toFixed(2)}%</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: seriesName,
|
||||
type: 'pie',
|
||||
radius: ['50%', '70%'],
|
||||
center: ['50%', '55%'],
|
||||
color: CHART_CONFIG.pieColors,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
distance: 15,
|
||||
fontSize: 11,
|
||||
color: CHART_CONFIG.lightFontColor,
|
||||
formatter: (params) => {
|
||||
const truncatedName = this.truncateText(params.name, 8);
|
||||
return `${truncatedName}(${params.value}${type === 'duration' ? '' : '次'}, ${params.percent.toFixed(1)}%)`;
|
||||
},
|
||||
align: 'center',
|
||||
baseline: 'middle'
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 15,
|
||||
length2: 20,
|
||||
lineStyle: {
|
||||
color: '#ccc',
|
||||
width: 1,
|
||||
type: 'solid'
|
||||
},
|
||||
smooth: 0.2
|
||||
},
|
||||
data: pieData,
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)'
|
||||
},
|
||||
label: {
|
||||
color: CHART_CONFIG.fontColor,
|
||||
fontSize: 12,
|
||||
fontWeight: 500
|
||||
},
|
||||
labelLine: {
|
||||
lineStyle: {
|
||||
color: CHART_CONFIG.barColor,
|
||||
width: 1.5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
this.chartInstances.pie.setOption(option);
|
||||
this.addResizeListener('pie');
|
||||
} catch (error) {
|
||||
console.error(`${seriesName}饼图初始化失败:`, error);
|
||||
setTimeout(() => this.renderPieChart(type), 200);
|
||||
}
|
||||
},
|
||||
|
||||
// 通用饼图数据处理(支持动态字段)
|
||||
handlePieData(data, valueKey, ratioKey) {
|
||||
const threshold = 5; // 占比低于5%合并为「其他」
|
||||
let otherCount = 0;
|
||||
const mainData = data.filter(item => {
|
||||
if (item[ratioKey] >= threshold) {
|
||||
return true;
|
||||
} else {
|
||||
otherCount += item[valueKey];
|
||||
return false;
|
||||
}
|
||||
}).map(item => ({
|
||||
name: item.alarmContent,
|
||||
value: item[valueKey],
|
||||
ratio: item[ratioKey]
|
||||
}));
|
||||
|
||||
if (otherCount > 0) {
|
||||
mainData.push({
|
||||
name: '其他',
|
||||
value: otherCount,
|
||||
ratio: 100 - mainData.reduce((sum, item) => sum + item.ratio, 0)
|
||||
});
|
||||
}
|
||||
|
||||
return mainData;
|
||||
},
|
||||
|
||||
truncateText(text, maxLength) {
|
||||
if (!text) return '';
|
||||
return text.length > maxLength ? text.slice(0, maxLength) + '...' : text;
|
||||
},
|
||||
|
||||
addResizeListener(type) {
|
||||
const chart = this.chartInstances[type];
|
||||
if (chart) {
|
||||
const resizeHandler = () => chart.resize();
|
||||
window.addEventListener('resize', resizeHandler);
|
||||
chart.resizeHandler = resizeHandler;
|
||||
}
|
||||
},
|
||||
|
||||
destroyChart(type) {
|
||||
const chart = this.chartInstances[type];
|
||||
if (chart) {
|
||||
window.removeEventListener('resize', chart.resizeHandler);
|
||||
chart.dispose();
|
||||
this.chartInstances[type] = null;
|
||||
}
|
||||
},
|
||||
|
||||
destroyAllCharts() {
|
||||
Object.keys(this.chartInstances).forEach(type => {
|
||||
this.destroyChart(type);
|
||||
});
|
||||
},
|
||||
|
||||
handleClose() {
|
||||
this.destroyAllCharts();
|
||||
this.formConfig[0].defaultSelect = [];
|
||||
this.listQuery.startTime = undefined;
|
||||
this.listQuery.endTime = undefined;
|
||||
this.originData = null;
|
||||
this.hasData = true;
|
||||
// 修复点2:增加多层判断,确保对象存在后再赋值
|
||||
if (this.$refs.searchBarForm && this.$refs.searchBarForm.form) {
|
||||
this.$refs.searchBarForm.form.timeVal = [];
|
||||
}
|
||||
},
|
||||
|
||||
init(data) {
|
||||
this.dataForm = {
|
||||
equipmentId: data.equipmentId || '',
|
||||
equipmentName: data.equipmentName || '',
|
||||
lineId: data.lineId || ''
|
||||
};
|
||||
this.activeLabel = 'duration'
|
||||
this.listQuery.equipmentId = data.equipmentId || undefined;
|
||||
this.visible = true;
|
||||
this.originData = null;
|
||||
this.hasData = false;
|
||||
|
||||
this.initDefaultDate();
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$nextTick(() => {
|
||||
this.isDomReady = true;
|
||||
this.getDataList();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.destroyAllCharts();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 保持原有样式,优化图表容器布局 */
|
||||
.drawer>>>.el-drawer {
|
||||
border-radius: 8px 0 0 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer>>>.el-form-item__label {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.drawer>>>.el-drawer__header {
|
||||
margin: 0;
|
||||
padding: 32px 32px 24px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.drawer>>>.el-drawer__body {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer>>>.content {
|
||||
padding: 30px 24px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer>>>.visual-part {
|
||||
flex: 1 auto;
|
||||
max-height: 76vh;
|
||||
overflow: hidden;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
/* 优化图表容器响应式布局 */
|
||||
@media (max-width: 1200px) {
|
||||
.visual-part>div {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#barChart,
|
||||
#pieChart {
|
||||
width: 100% !important;
|
||||
height: 350px !important;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer>>>.el-form,
|
||||
.drawer>>>.attr-list {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.drawer-body__footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 18px;
|
||||
}
|
||||
</style>
|
||||
1308
src/views/equipment/equipmentOverview/index.vue
Normal file
1308
src/views/equipment/equipmentOverview/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
309
src/views/quality/dpdda/defectAnalysis.vue
Normal file
309
src/views/quality/dpdda/defectAnalysis.vue
Normal file
@@ -0,0 +1,309 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索工作栏 -->
|
||||
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" @headBtnClick="handleSearchBarBtnClick" />
|
||||
|
||||
<!-- 列表 -->
|
||||
<base-table :table-props="tableProps" :page="queryParams.pageNo" :limit="queryParams.pageSize" :table-data="list"
|
||||
@emitFun="handleEmitFun">
|
||||
<!-- <method-btn v-if="tableBtn.length" slot="handleBtn" label="操作" :width="120" :method-list="tableBtn"
|
||||
@clickBtn="handleTableBtnClick" /> -->
|
||||
</base-table>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList" />
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
|
||||
import {
|
||||
getPdList,
|
||||
} from '@/api/core/monitoring/auto';
|
||||
import { getFactoryPage } from '@/api/core/base/factory';
|
||||
import basicPageMixin from '@/mixins/lb/basicPageMixin';
|
||||
import { getDefectAnalysis } from '@/api/monitoring/defectSummary';
|
||||
import * as XLSX from 'xlsx'
|
||||
import FileSaver from 'file-saver'
|
||||
export default {
|
||||
name: 'QualityInspectionType',
|
||||
mixins: [basicPageMixin],
|
||||
data() {
|
||||
return {
|
||||
// tableBtn: [
|
||||
// this.$auth.hasPermi('base:quality-inspection-type:update')
|
||||
// ? {
|
||||
// type: 'edit',
|
||||
// btnName: '修改',
|
||||
// }
|
||||
// : undefined,
|
||||
// this.$auth.hasPermi('base:quality-inspection-type:delete')
|
||||
// ? {
|
||||
// type: 'delete',
|
||||
// btnName: '删除',
|
||||
// }
|
||||
// : undefined,
|
||||
// ].filter((v) => v),
|
||||
tableProps: [
|
||||
// {
|
||||
// prop: 'createTime',
|
||||
// label: '添加时间',
|
||||
// fixed: true,
|
||||
// width: 180,
|
||||
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
|
||||
// },
|
||||
{ prop: 'factoryName', label: '工厂' },
|
||||
{ prop: 'lineName', label: '产线' },
|
||||
{ prop: 'remark', label: '玻璃编号' },
|
||||
{
|
||||
prop: 'checkTime',
|
||||
label: '检测时间',
|
||||
fixed: true,
|
||||
width: 180,
|
||||
filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
|
||||
},
|
||||
{ prop: 'checkNum', label: '缺陷数' },
|
||||
{
|
||||
prop: 'glassGrade',
|
||||
label: '等级',
|
||||
filter: (val) => val === 0 ? '合格' : val === 1 ? '提示' : val === 2 ? '返修' : val === 3 ? '报废' : ''
|
||||
},
|
||||
{ prop: 'reason', label: '判等原因' },
|
||||
{ prop: 'specifications', label: '规格' },
|
||||
|
||||
|
||||
// {
|
||||
// label: '操作',
|
||||
// alignt: 'center',
|
||||
// subcomponent: {
|
||||
// render: function (h) {
|
||||
// return h('div', null, [
|
||||
// h(
|
||||
// 'el-button',
|
||||
// {
|
||||
// props: {
|
||||
// icon: 'el-icon-edit',
|
||||
// size: 'mini',
|
||||
// type: 'text',
|
||||
// },
|
||||
// },
|
||||
// ' 修改'
|
||||
// ),
|
||||
// h(
|
||||
// 'el-button',
|
||||
// {
|
||||
// props: {
|
||||
// icon: 'el-icon-edit',
|
||||
// size: 'mini',
|
||||
// type: 'text',
|
||||
// },
|
||||
// },
|
||||
// ' 修改'
|
||||
// ),
|
||||
// ]);
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
],
|
||||
//
|
||||
searchBarFormConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '工厂',
|
||||
selectOptions: [],
|
||||
param: 'factoryId',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
param: 'lineId',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: '缺陷数>',
|
||||
// selectOptions: [],
|
||||
param: 'checkNum',
|
||||
},
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'datetimerange',
|
||||
format: 'yyyy-MM-dd HH:mm:ss',
|
||||
// valueFormat: 'timestamp',
|
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
width: 350
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
// {
|
||||
// type: 'button',
|
||||
// btnName: '重置',
|
||||
// name: 'reset',
|
||||
// },
|
||||
{
|
||||
type: 'separate',
|
||||
},
|
||||
// {
|
||||
// type: this.$auth.hasPermi('base:quality-inspection-type:create')
|
||||
// ? 'button'
|
||||
// : '',
|
||||
// btnName: '新增',
|
||||
// name: 'add',
|
||||
// plain: true,
|
||||
// color: 'success',
|
||||
// },
|
||||
{
|
||||
type: this.$auth.hasPermi('base:quality-inspection-type:export')
|
||||
? 'button'
|
||||
: '',
|
||||
btnName: '导出',
|
||||
name: 'export',
|
||||
color: 'warning',
|
||||
},
|
||||
],
|
||||
// 表单配置
|
||||
// formRows: [
|
||||
// [
|
||||
// {
|
||||
// input: true,
|
||||
// label: '检测类型名称',
|
||||
// prop: 'name',
|
||||
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
|
||||
// // bind: {
|
||||
// // disabled: true, // some condition, like detail mode...
|
||||
// // }
|
||||
// },
|
||||
// ],
|
||||
// [{ input: true, label: '检测类型编码', prop: 'code' }],
|
||||
// [{ input: true, label: '备注', prop: 'remark' }],
|
||||
// ],
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
lineId: undefined,
|
||||
factoryId: undefined,
|
||||
checkNum: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
};
|
||||
},
|
||||
// watch: {
|
||||
// form: {
|
||||
// handler: (val) => {
|
||||
// console.log('form changed', val);
|
||||
// },
|
||||
// deep: true
|
||||
// },
|
||||
// },
|
||||
created() {
|
||||
this.getList();
|
||||
this.getDict()
|
||||
},
|
||||
methods: {
|
||||
getDict() {
|
||||
getPdList().then(res => {
|
||||
this.searchBarFormConfig[1].selectOptions = res.data || [];
|
||||
});
|
||||
|
||||
getFactoryPage({ pageSize: 100, pageNo: 1 }).then(res => {
|
||||
this.searchBarFormConfig[0].selectOptions = res.data.list || [];
|
||||
});
|
||||
},
|
||||
/** base table related */
|
||||
handleTableBtnClick({ data, type }) {
|
||||
switch (type) {
|
||||
case 'edit':
|
||||
this.handleUpdate(data);
|
||||
break;
|
||||
case 'delete':
|
||||
this.handleDelete(data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
/** search bar related */
|
||||
handleSearchBarBtnClick(btn) {
|
||||
// const keys = ['name'];
|
||||
switch (btn.btnName) {
|
||||
case 'search':
|
||||
this.queryParams.lineId = btn.lineId ? btn.lineId : undefined
|
||||
this.queryParams.factoryId = btn.factoryId ? btn.factoryId : undefined
|
||||
this.queryParams.startTime = btn.timeVal ? btn.timeVal[0] : undefined
|
||||
this.queryParams.endTime = btn.timeVal ? btn.timeVal[1] : undefined
|
||||
this.queryParams.checkNum = btn.checkNum ? btn.checkNum : undefined
|
||||
|
||||
|
||||
// keys.forEach((key) => {
|
||||
// this.queryParams[key] = btn[key] || null;
|
||||
// });
|
||||
this.getList();
|
||||
break;
|
||||
case 'add':
|
||||
this.handleAdd();
|
||||
break;
|
||||
case 'export':
|
||||
this.handleExport();
|
||||
break;
|
||||
// case 'reset':
|
||||
// this.$refs['search-bar'].resetForm();
|
||||
// this.resetQuery();
|
||||
// break;
|
||||
}
|
||||
},
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 执行查询
|
||||
getDefectAnalysis(this.queryParams).then((response) => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
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'
|
||||
}),'缺陷分析.xlsx')
|
||||
} catch (e) {
|
||||
if (typeof console !== 'undefined') console.log(e, exportTableOut)
|
||||
}
|
||||
return exportTableOut
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
560
src/views/quality/dpdda/defectSummary.vue
Normal file
560
src/views/quality/dpdda/defectSummary.vue
Normal file
@@ -0,0 +1,560 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索工作栏 -->
|
||||
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" @headBtnClick="handleSearchBarBtnClick" />
|
||||
|
||||
<!-- 列表 -->
|
||||
<base-table :table-props="tableProps" :page="queryParams.pageNo" :limit="queryParams.pageSize" :table-data="list"
|
||||
@emitFun="handleEmitFun">
|
||||
<method-btn v-if="tableBtn.length" slot="handleBtn" label="操作" :width="120" :method-list="tableBtn"
|
||||
@clickBtn="handleTableBtnClick" />
|
||||
</base-table>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList" />
|
||||
<div v-if="chartData" class="charts-container">
|
||||
<div v-for="(lineData, lineName) in chartData" :key="lineName" class="chart-wrapper">
|
||||
<div class="blue-block"></div>
|
||||
<h3 class="chart-title">{{ lineName }}</h3>
|
||||
<div :id="`chart-${lineName}`" class="chart" style="width: 100%; height: 300px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<defect-summary-det ref="defectSummaryDetRef" v-if="defectVis" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
|
||||
import {
|
||||
getPdList,
|
||||
} from '@/api/core/monitoring/auto';
|
||||
import { getFactoryPage } from '@/api/core/base/factory';
|
||||
import { getDefectSummaryTable, getDefectSummaryChart } from '@/api/monitoring/defectSummary';
|
||||
import * as echarts from 'echarts';
|
||||
import basicPageMixin from '@/mixins/lb/basicPageMixin';
|
||||
import defectSummaryDet from './defectSummaryDet.vue'
|
||||
export default {
|
||||
name: 'QualityInspectionType',
|
||||
mixins: [basicPageMixin],
|
||||
components: {
|
||||
defectSummaryDet
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableBtn: [
|
||||
this.$auth.hasPermi('base:quality-inspection-type:update')
|
||||
? {
|
||||
type: 'detail',
|
||||
btnName: '缺陷详情',
|
||||
}
|
||||
: undefined,
|
||||
// this.$auth.hasPermi('base:quality-inspection-type:delete')
|
||||
// ? {
|
||||
// type: 'delete',
|
||||
// btnName: '删除',
|
||||
// }
|
||||
// : undefined,
|
||||
].filter((v) => v),
|
||||
tableProps: [
|
||||
// {
|
||||
// prop: 'createTime',
|
||||
// label: '添加时间',
|
||||
// fixed: true,
|
||||
// width: 180,
|
||||
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
|
||||
// },
|
||||
{ prop: 'factoryName', label: '工厂' },
|
||||
{ prop: 'lineName', label: '产线' },
|
||||
{ prop: 'glassNum', label: '玻璃总数' },
|
||||
{
|
||||
prop: 'okNum',
|
||||
label: '合格品数',
|
||||
},
|
||||
{ prop: 'okRate', label: '合格百分比' },
|
||||
{ prop: 'repairNum', label: '返修品数' },
|
||||
{ prop: 'repairRate', label: '返修百分比' },
|
||||
{ prop: 'ngNum', label: '废片数' },
|
||||
{ prop: 'ngRate', label: '废片百分比' },
|
||||
{ prop: 'oneNgNum', label: '1类缺陷玻璃数量' },
|
||||
{ prop: 'twoNgNum', label: '2类缺陷玻璃数量' },
|
||||
{ prop: 'threeNgNum', label: '3类缺陷玻璃数量' },
|
||||
|
||||
|
||||
|
||||
|
||||
// {
|
||||
// label: '操作',
|
||||
// alignt: 'center',
|
||||
// subcomponent: {
|
||||
// render: function (h) {
|
||||
// return h('div', null, [
|
||||
// h(
|
||||
// 'el-button',
|
||||
// {
|
||||
// props: {
|
||||
// icon: 'el-icon-edit',
|
||||
// size: 'mini',
|
||||
// type: 'text',
|
||||
// },
|
||||
// },
|
||||
// ' 修改'
|
||||
// ),
|
||||
// h(
|
||||
// 'el-button',
|
||||
// {
|
||||
// props: {
|
||||
// icon: 'el-icon-edit',
|
||||
// size: 'mini',
|
||||
// type: 'text',
|
||||
// },
|
||||
// },
|
||||
// ' 修改'
|
||||
// ),
|
||||
// ]);
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
],
|
||||
//
|
||||
searchBarFormConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '工厂',
|
||||
selectOptions: [],
|
||||
param: 'factoryId',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
multiple: true,
|
||||
param: 'lineId',
|
||||
},
|
||||
// {
|
||||
// type: 'input',
|
||||
// label: '缺陷数>',
|
||||
// // selectOptions: [],
|
||||
// param: 'number',
|
||||
// },
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'datetimerange',
|
||||
format: 'yyyy-MM-dd HH:mm:ss',
|
||||
// valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||
valueFormat: 'timestamp',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
width: 350
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
// {
|
||||
// type: 'button',
|
||||
// btnName: '重置',
|
||||
// name: 'reset',
|
||||
// },
|
||||
{
|
||||
type: 'separate',
|
||||
},
|
||||
// {
|
||||
// type: this.$auth.hasPermi('base:quality-inspection-type:create')
|
||||
// ? 'button'
|
||||
// : '',
|
||||
// btnName: '新增',
|
||||
// name: 'add',
|
||||
// plain: true,
|
||||
// color: 'success',
|
||||
// },
|
||||
{
|
||||
type: this.$auth.hasPermi('base:quality-inspection-type:export')
|
||||
? 'button'
|
||||
: '',
|
||||
btnName: '导出',
|
||||
name: 'export',
|
||||
color: 'warning',
|
||||
},
|
||||
],
|
||||
// 表单配置
|
||||
// formRows: [
|
||||
// [
|
||||
// {
|
||||
// input: true,
|
||||
// label: '检测类型名称',
|
||||
// prop: 'name',
|
||||
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
|
||||
// // bind: {
|
||||
// // disabled: true, // some condition, like detail mode...
|
||||
// // }
|
||||
// },
|
||||
// ],
|
||||
// [{ input: true, label: '检测类型编码', prop: 'code' }],
|
||||
// [{ input: true, label: '备注', prop: 'remark' }],
|
||||
// ],
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
chartData: {},
|
||||
charts: {},
|
||||
defectVis:false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
lineId: undefined,
|
||||
factoryId: undefined,
|
||||
checkNum: undefined,
|
||||
startTime: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
};
|
||||
},
|
||||
// watch: {
|
||||
// form: {
|
||||
// handler: (val) => {
|
||||
// console.log('form changed', val);
|
||||
// },
|
||||
// deep: true
|
||||
// },
|
||||
// },
|
||||
created() {
|
||||
this.getList();
|
||||
this.getDict()
|
||||
},
|
||||
methods: {
|
||||
getDict() {
|
||||
getPdList().then(res => {
|
||||
this.searchBarFormConfig[1].selectOptions = res.data || [];
|
||||
});
|
||||
|
||||
getFactoryPage({ pageSize: 100, pageNo: 1 }).then(res => {
|
||||
this.searchBarFormConfig[0].selectOptions = res.data.list || [];
|
||||
});
|
||||
},
|
||||
/** base table related */
|
||||
handleTableBtnClick({ data, type }) {
|
||||
switch (type) {
|
||||
case 'detail':
|
||||
this.defectVis = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.defectSummaryDetRef.init({
|
||||
factoryId:data.factoryId,
|
||||
lineId: [data.lineId],
|
||||
factoryName: data.factoryName,
|
||||
lineName: data.lineName,
|
||||
startTime: this.queryParams.startTime,
|
||||
endTime: this.queryParams.endTime,
|
||||
|
||||
})
|
||||
})
|
||||
break;
|
||||
case 'delete':
|
||||
this.handleDelete(data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 销毁所有 ECharts 实例
|
||||
Object.values(this.charts).forEach(chart => {
|
||||
if (chart && chart.dispose) {
|
||||
chart.dispose();
|
||||
}
|
||||
});
|
||||
this.charts = {};
|
||||
},
|
||||
/**
|
||||
* 初始化单个图表
|
||||
* @param {string} lineName - 产线名称
|
||||
* @param {Array} lineData - 该产线的原始数据
|
||||
*/
|
||||
initSingleChart(lineName, lineData) {
|
||||
// 如果已有实例,先销毁
|
||||
if (this.charts[lineName]) {
|
||||
this.charts[lineName].dispose();
|
||||
}
|
||||
|
||||
const chartDom = document.getElementById(`chart-${lineName}`);
|
||||
if (!chartDom || !lineData || lineData.length === 0) {
|
||||
console.warn(`图表容器 chart-${lineName} 未找到或数据为空`);
|
||||
return;
|
||||
}
|
||||
|
||||
const myChart = echarts.init(chartDom);
|
||||
|
||||
// --- 动态处理数据逻辑 ---
|
||||
const startTime = this.queryParams.startTime;
|
||||
const endTime = this.queryParams.endTime;
|
||||
|
||||
if (!startTime || !endTime) {
|
||||
console.error("起始时间或结束时间为空,无法计算时间差。");
|
||||
return;
|
||||
}
|
||||
|
||||
const durationDays = (endTime - startTime) / (1000 * 60 * 60 * 24);
|
||||
const isHourly = durationDays < 7;
|
||||
|
||||
// 使用Map来保证顺序,并能存储聚合后的数据和原始显示标签
|
||||
const aggregatedMap = new Map();
|
||||
|
||||
lineData.forEach(item => {
|
||||
let groupKey; // 用于分组的键
|
||||
let displayLabel; // 用于显示的标签
|
||||
|
||||
if (isHourly) {
|
||||
// --- 方法一:使用字符串分割 ---
|
||||
const timePart = item.timePoint.split('T')[1];
|
||||
groupKey = timePart ? timePart : item.timePoint; // 安全处理
|
||||
|
||||
displayLabel = item.timePoint.replace('T', ' ');
|
||||
} else {
|
||||
// 按天聚合:分组键和显示标签都到天
|
||||
groupKey = item.timePoint.split('T')[0];
|
||||
displayLabel = groupKey;
|
||||
}
|
||||
|
||||
if (!aggregatedMap.has(groupKey)) {
|
||||
aggregatedMap.set(groupKey, {
|
||||
displayLabel: displayLabel,
|
||||
okNum: 0,
|
||||
repairNum: 0,
|
||||
ngNum: 0
|
||||
});
|
||||
}
|
||||
|
||||
const aggregatedItem = aggregatedMap.get(groupKey);
|
||||
aggregatedItem.okNum += item.okNum || 0;
|
||||
aggregatedItem.repairNum += item.repairNum || 0;
|
||||
aggregatedItem.ngNum += item.ngNum || 0;
|
||||
});
|
||||
|
||||
// 准备 ECharts 所需的数据格式
|
||||
const xAxisData = [];
|
||||
const okNumData = [];
|
||||
const repairNumData = [];
|
||||
const ngNumData = [];
|
||||
|
||||
aggregatedMap.forEach(item => {
|
||||
xAxisData.push(item.displayLabel);
|
||||
okNumData.push(item.okNum);
|
||||
repairNumData.push(item.repairNum);
|
||||
ngNumData.push(item.ngNum);
|
||||
});
|
||||
|
||||
// --- ECharts 配置项 ---
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'cross' },
|
||||
},
|
||||
legend: {
|
||||
data: ['合格品数', '返修品数', '废片数'],
|
||||
itemHeight: 2,
|
||||
itemWidth: 20,
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '20%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: xAxisData,
|
||||
axisLabel: {
|
||||
rotate: 45,
|
||||
interval: 0, // 强制显示所有标签
|
||||
formatter: function (value) {
|
||||
if (isHourly) {
|
||||
// 从 "2025-10-30 00:00" 中提取 "00:00" 进行显示
|
||||
return value.split(' ')[1];
|
||||
} else {
|
||||
// 天级别,显示 "MM-DD"
|
||||
const dateParts = value.split('-');
|
||||
return `${dateParts[1]}-${dateParts[2]}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '合格品数',
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
data: okNumData,
|
||||
itemStyle: { color: 'rgba(40, 138, 255, 1)' },
|
||||
},
|
||||
{
|
||||
name: '返修品数',
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
data: repairNumData,
|
||||
itemStyle: { color: 'rgba(115, 222, 147, 1)' },
|
||||
},
|
||||
{
|
||||
name: '废片数',
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
data: ngNumData,
|
||||
itemStyle: { color: 'rgba(255, 206, 106, 1)' },
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
myChart.setOption(option);
|
||||
this.charts[lineName] = myChart;
|
||||
|
||||
// 监听容器大小变化
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
myChart.resize();
|
||||
});
|
||||
resizeObserver.observe(chartDom);
|
||||
myChart._resizeObserver = resizeObserver;
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据获取到的 chartData 更新所有图表
|
||||
*/
|
||||
updateAllCharts() {
|
||||
if (!this.chartData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用 nextTick 确保 v-for 生成的 DOM 已存在
|
||||
this.$nextTick(() => {
|
||||
const lineNames = Object.keys(this.chartData);
|
||||
lineNames.forEach(lineName => {
|
||||
this.initSingleChart(lineName, this.chartData[lineName]);
|
||||
});
|
||||
});
|
||||
},
|
||||
/** search bar related */
|
||||
handleSearchBarBtnClick(btn) {
|
||||
switch (btn.btnName) {
|
||||
case 'search':
|
||||
this.queryParams.lineId = btn.lineId ? btn.lineId : undefined
|
||||
this.queryParams.factoryId = btn.factoryId ? btn.factoryId : undefined
|
||||
this.queryParams.startTime = btn.timeVal ? btn.timeVal[0] : undefined
|
||||
this.queryParams.endTime = btn.timeVal ? btn.timeVal[1] : undefined
|
||||
this.getList();
|
||||
break;
|
||||
case 'add':
|
||||
this.handleAdd();
|
||||
break;
|
||||
case 'export':
|
||||
this.handleExport();
|
||||
break;
|
||||
// case 'reset':
|
||||
// this.$refs['search-bar'].resetForm();
|
||||
// this.resetQuery();
|
||||
// break;
|
||||
}
|
||||
},
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 执行查询
|
||||
getDefectSummaryTable(this.queryParams).then((response) => {
|
||||
this.list = response.data;
|
||||
// this.total = response.data.total;
|
||||
this.loading = false;
|
||||
})
|
||||
getDefectSummaryChart(this.queryParams).then((res) => {
|
||||
console.log('res.data', res.data);
|
||||
|
||||
this.chartData = res.data || {};
|
||||
// 手动调用更新图表的方法
|
||||
this.updateAllCharts();
|
||||
// // this.total = response.data.total;
|
||||
// this.loading = false;
|
||||
})
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
code: undefined,
|
||||
remark: undefined,
|
||||
};
|
||||
this.resetForm('form');
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
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'
|
||||
}), '缺陷汇总.xlsx')
|
||||
} catch (e) {
|
||||
if (typeof console !== 'undefined') console.log(e, exportTableOut)
|
||||
}
|
||||
return exportTableOut
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.charts-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chart-wrapper {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
margin-top: 10px;
|
||||
/* 最小宽度,防止缩得太小 */
|
||||
/* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px; */
|
||||
/* padding: 10px; */
|
||||
}
|
||||
|
||||
.blue-block {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #0B58FF;
|
||||
border-radius: 1px;
|
||||
margin-right: 8px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
text-align: left;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
224
src/views/quality/dpdda/defectSummaryDet.vue
Normal file
224
src/views/quality/dpdda/defectSummaryDet.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer title="详情" :visible.sync="visible" size="70%" @close='closeD'>
|
||||
<div class="box">
|
||||
<!-- 顶部信息展示区域 -->
|
||||
<div class="info-header">
|
||||
<div class="info-item">
|
||||
<span class="label">工厂:</span>
|
||||
<span class="value">{{ factoryName }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">产线:</span>
|
||||
<span class="value">{{ lineName }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">时间范围:</span>
|
||||
<span class="value">{{ timeRange }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<el-button type="primary" @click="handleExport">导出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<base-table :page="queryParams.pageNo" :limit="queryParams.pageSize" :table-props="tableProps"
|
||||
:table-data="tableData" :span-method="spanMethod" :max-height="tableH">
|
||||
</base-table>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import * as XLSX from 'xlsx';
|
||||
import { getDefectSummaryDet } from '@/api/monitoring/defectSummary';
|
||||
// import { publicFormatter } from '@/utils/dict'
|
||||
|
||||
const tableProps = [
|
||||
{ prop: 'defectLevel', label: '缺陷等级' },
|
||||
{ prop: 'defectName', label: '缺陷类型' },
|
||||
{ prop: 'defectNum', label: '玻璃数量' }
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'EnergyStatisticsDet',
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
tableProps,
|
||||
tableData: [],
|
||||
tableBtn: [],
|
||||
tableH: this.tableHeight(115),
|
||||
total: 0,
|
||||
queryParams: { pageNo: 1, pageSize: 30 },
|
||||
factoryName: '',
|
||||
lineName: '',
|
||||
timeRange: '',
|
||||
name: '',
|
||||
energyType: '',
|
||||
energyTypeId: '',
|
||||
addOrEditTitle: "",
|
||||
centervisible: false,
|
||||
collectionList: [
|
||||
{ value: 0, label: '否' },
|
||||
{ value: 1, label: '是' }
|
||||
],
|
||||
showBtn: true,
|
||||
selectedList: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
window.addEventListener('resize', () => {
|
||||
this.tableH = this.tableHeight(115)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
spanMethod({ row, column, rowIndex, columnIndex }) {
|
||||
const fields = ['defectLevel']
|
||||
const cellValue = row[column.property]
|
||||
if (cellValue && fields.includes(column.property)) {
|
||||
const prevRow = this.tableData[rowIndex - 1]
|
||||
let nextRow = this.tableData[rowIndex + 1]
|
||||
if (prevRow && prevRow[column.property] === cellValue) {
|
||||
return { rowspan: 0, colspan: 0 }
|
||||
} else {
|
||||
let countRowspan = 1
|
||||
while (nextRow && nextRow[column.property] === cellValue) {
|
||||
nextRow = this.tableData[++countRowspan + rowIndex]
|
||||
}
|
||||
if (countRowspan > 1) {
|
||||
return { rowspan: countRowspan, colspan: 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
init(data) {
|
||||
this.visible = true;
|
||||
this.factoryName = data.factoryName || '未知工厂';
|
||||
this.lineName = data.lineName || '未知产线';
|
||||
|
||||
if (data.startTime && data.endTime) {
|
||||
const start = moment(data.startTime).format('yyyy-MM-DD HH:mm:ss');
|
||||
const end = moment(data.endTime).format('yyyy-MM-DD HH:mm:ss');
|
||||
this.timeRange = `${start} - ${end}`;
|
||||
} else {
|
||||
this.timeRange = '';
|
||||
}
|
||||
|
||||
this.queryParams.factoryId = data.factoryId;
|
||||
this.queryParams.lineId = data.lineId;
|
||||
this.queryParams.startTime = data.startTime;
|
||||
this.queryParams.endTime = data.endTime;
|
||||
|
||||
this.getList();
|
||||
},
|
||||
|
||||
getList() {
|
||||
getDefectSummaryDet({ ...this.queryParams }).then((res) => {
|
||||
this.tableData = res.data || [];
|
||||
})
|
||||
},
|
||||
|
||||
closeD() {
|
||||
this.$emit('closeDrawer');
|
||||
},
|
||||
|
||||
closeDet() {
|
||||
this.getList();
|
||||
},
|
||||
|
||||
// --- 重写的导出方法 ---
|
||||
// --- 修改后的导出方法 ---
|
||||
handleExport() {
|
||||
console.log("开始执行导出...");
|
||||
this.$modal.confirm('确定要导出表格数据吗?').then(() => {
|
||||
console.log("用户确认导出");
|
||||
|
||||
// 1. 准备数据
|
||||
console.log("tableProps:", this.tableProps);
|
||||
console.log("tableData:", this.tableData);
|
||||
|
||||
// 1.1 准备表头 (新增了 '工厂', '产线', '时间范围')
|
||||
const headers = ['工厂', '产线', '时间范围', ...this.tableProps.map(prop => prop.label)];
|
||||
console.log("生成的表头:", headers);
|
||||
|
||||
// 1.2 准备表格数据
|
||||
const exportData = [];
|
||||
this.tableData.forEach((row) => {
|
||||
const newRow = [];
|
||||
// 先添加顶部信息列
|
||||
newRow.push(this.factoryName);
|
||||
newRow.push(this.lineName);
|
||||
newRow.push(this.timeRange);
|
||||
|
||||
// 再添加表格数据列
|
||||
this.tableProps.forEach((prop) => {
|
||||
// 直接填入所有数据,不再对 defectLevel 进行合并判断
|
||||
newRow.push(row[prop.prop] !== undefined ? row[prop.prop] : '');
|
||||
});
|
||||
exportData.push(newRow);
|
||||
});
|
||||
console.log("处理后的数据:", exportData);
|
||||
|
||||
// 2. 创建工作簿和工作表
|
||||
try {
|
||||
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...exportData]);
|
||||
console.log("工作表创建成功");
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '缺陷详情数据');
|
||||
console.log("工作簿创建成功");
|
||||
|
||||
// 3. 触发下载
|
||||
const fileName = `${this.factoryName}-${this.lineName}-缺陷汇总详情-${moment().format('YYYYMMDDHHmmss')}.xlsx`;
|
||||
console.log("准备下载文件:", fileName);
|
||||
XLSX.writeFile(workbook, fileName);
|
||||
console.log("下载触发成功");
|
||||
} catch (error) {
|
||||
console.error("生成Excel文件时出错:", error);
|
||||
this.$modal.msgError('导出失败,生成文件时出错!');
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log("用户取消导出或发生错误:", error);
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
.info-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 32px;
|
||||
font-size: 16px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.label {
|
||||
color: #606266;
|
||||
margin-right: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
416
src/views/quality/dpdda/sectionDefect.vue
Normal file
416
src/views/quality/dpdda/sectionDefect.vue
Normal file
@@ -0,0 +1,416 @@
|
||||
<template>
|
||||
<div 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;
|
||||
">
|
||||
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" @headBtnClick="handleSearchBarBtnClick" />
|
||||
<base-table :max-height="tableH" :table-props="tableProps" :page="queryParams.pageNo"
|
||||
:limit="queryParams.pageSize" :table-data="list" @emitFun="handleEmitFun" />
|
||||
</el-row>
|
||||
<!-- 搜索工作栏 -->
|
||||
|
||||
<!-- 用一个 div 包裹表格和图表,并使用 flex 布局 -->
|
||||
<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="24">
|
||||
<div id="chart" style="width: 100%; height: 300px;"></div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getPdList,
|
||||
} from '@/api/core/monitoring/auto';
|
||||
import { getFactoryPage } from '@/api/core/base/factory';
|
||||
import basicPageMixin from '@/mixins/lb/basicPageMixin';
|
||||
import { getSectionDefect } from '@/api/monitoring/defectSummary';
|
||||
import * as echarts from 'echarts';
|
||||
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
|
||||
export default {
|
||||
name: 'QualityInspectionType',
|
||||
mixins: [basicPageMixin, tableHeightMixin],
|
||||
data() {
|
||||
return {
|
||||
tableBtn: [
|
||||
this.$auth.hasPermi('base:quality-inspection-type:update')
|
||||
? {
|
||||
type: 'edit',
|
||||
btnName: '修改',
|
||||
}
|
||||
: undefined,
|
||||
this.$auth.hasPermi('base:quality-inspection-type:delete')
|
||||
? {
|
||||
type: 'delete',
|
||||
btnName: '删除',
|
||||
}
|
||||
: undefined,
|
||||
].filter((v) => v),
|
||||
tableProps: [
|
||||
// {
|
||||
// prop: 'createTime',
|
||||
// label: '添加时间',
|
||||
// fixed: true,
|
||||
// width: 180,
|
||||
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
|
||||
// },
|
||||
{ prop: 'factoryName', label: '工厂' },
|
||||
{ prop: 'lineName', label: '产线' },
|
||||
{ prop: 'checkCount', label: '检测片数' },
|
||||
{
|
||||
prop: 'ngCount',
|
||||
label: '不良合计',
|
||||
},
|
||||
{
|
||||
prop: 'ngRate',
|
||||
label: '不良率',
|
||||
},
|
||||
{ prop: 'originalNgCount', label: '原片不良' },
|
||||
{ prop: 'edgeNgCount', label: '磨边不良' },
|
||||
{ prop: 'silkNgCount', label: '丝印不良' },
|
||||
{ prop: 'drillNgCount', label: '打孔不良' },
|
||||
{ prop: 'coatingNgCount', label: '镀膜不良' },
|
||||
{ prop: 'packNgCount', label: '钢包不良' },
|
||||
|
||||
|
||||
|
||||
// {
|
||||
// label: '操作',
|
||||
// alignt: 'center',
|
||||
// subcomponent: {
|
||||
// render: function (h) {
|
||||
// return h('div', null, [
|
||||
// h(
|
||||
// 'el-button',
|
||||
// {
|
||||
// props: {
|
||||
// icon: 'el-icon-edit',
|
||||
// size: 'mini',
|
||||
// type: 'text',
|
||||
// },
|
||||
// },
|
||||
// ' 修改'
|
||||
// ),
|
||||
// h(
|
||||
// 'el-button',
|
||||
// {
|
||||
// props: {
|
||||
// icon: 'el-icon-edit',
|
||||
// size: 'mini',
|
||||
// type: 'text',
|
||||
// },
|
||||
// },
|
||||
// ' 修改'
|
||||
// ),
|
||||
// ]);
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
],
|
||||
//
|
||||
searchBarFormConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '工厂',
|
||||
selectOptions: [],
|
||||
param: 'factoryId',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
multiple: true,
|
||||
param: 'lineId',
|
||||
},
|
||||
// {
|
||||
// type: 'input',
|
||||
// label: '缺陷数>',
|
||||
// // selectOptions: [],
|
||||
// param: 'number',
|
||||
// },
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'datetimerange',
|
||||
format: 'yyyy-MM-dd HH:mm:ss',
|
||||
valueFormat: 'timestamp',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
width: 350
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
// {
|
||||
// type: 'button',
|
||||
// btnName: '重置',
|
||||
// name: 'reset',
|
||||
// },
|
||||
{
|
||||
type: 'separate',
|
||||
},
|
||||
// {
|
||||
// type: this.$auth.hasPermi('base:quality-inspection-type:create')
|
||||
// ? 'button'
|
||||
// : '',
|
||||
// btnName: '新增',
|
||||
// name: 'add',
|
||||
// plain: true,
|
||||
// color: 'success',
|
||||
// },
|
||||
{
|
||||
type: this.$auth.hasPermi('base:quality-inspection-type:export')
|
||||
? 'button'
|
||||
: '',
|
||||
btnName: '导出',
|
||||
name: 'export',
|
||||
color: 'warning',
|
||||
},
|
||||
],
|
||||
// 表单配置
|
||||
// formRows: [
|
||||
// [
|
||||
// {
|
||||
// input: true,
|
||||
// label: '检测类型名称',
|
||||
// prop: 'name',
|
||||
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
|
||||
// // bind: {
|
||||
// // disabled: true, // some condition, like detail mode...
|
||||
// // }
|
||||
// },
|
||||
// ],
|
||||
// [{ input: true, label: '检测类型编码', prop: 'code' }],
|
||||
// [{ input: true, label: '备注', prop: 'remark' }],
|
||||
// ],
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
lineId: undefined,
|
||||
factoryId: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
};
|
||||
},
|
||||
// watch: {
|
||||
// form: {
|
||||
// handler: (val) => {
|
||||
// console.log('form changed', val);
|
||||
// },
|
||||
// deep: true
|
||||
// },
|
||||
// },
|
||||
created() {
|
||||
this.getList();
|
||||
this.getDict()
|
||||
},
|
||||
methods: {
|
||||
getDict() {
|
||||
getPdList().then(res => {
|
||||
this.searchBarFormConfig[1].selectOptions = res.data || [];
|
||||
});
|
||||
|
||||
getFactoryPage({ pageSize: 100, pageNo: 1 }).then(res => {
|
||||
this.searchBarFormConfig[0].selectOptions = res.data.list || [];
|
||||
});
|
||||
},
|
||||
/** base table related */
|
||||
handleTableBtnClick({ data, type }) {
|
||||
switch (type) {
|
||||
case 'edit':
|
||||
this.handleUpdate(data);
|
||||
break;
|
||||
case 'delete':
|
||||
this.handleDelete(data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
/** search bar related */
|
||||
handleSearchBarBtnClick(btn) {
|
||||
switch (btn.btnName) {
|
||||
case 'search':
|
||||
this.queryParams.lineId = btn.lineId ? btn.lineId : undefined
|
||||
this.queryParams.factoryId = btn.factoryId ? btn.factoryId : undefined
|
||||
this.queryParams.startTime = btn.timeVal ? btn.timeVal[0] : undefined
|
||||
this.queryParams.endTime = btn.timeVal ? btn.timeVal[1] : undefined
|
||||
this.getList();
|
||||
break;
|
||||
case 'add':
|
||||
this.handleAdd();
|
||||
break;
|
||||
case 'export':
|
||||
this.handleExport();
|
||||
break;
|
||||
case 'reset':
|
||||
this.$refs['search-bar'].resetForm();
|
||||
this.resetQuery();
|
||||
break;
|
||||
}
|
||||
},
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 执行查询
|
||||
getSectionDefect(this.queryParams).then((response) => {
|
||||
this.list = response.data;
|
||||
// 定义颜色数组,与你提供的顺序一致
|
||||
const colors = [
|
||||
'rgba(99, 189, 255, 1)',
|
||||
'rgba(113, 100, 255, 1)',
|
||||
'rgba(255, 104, 96, 1)',
|
||||
'rgba(255, 151, 71, 1)',
|
||||
'rgba(176, 235, 66, 1)',
|
||||
'rgba(214, 128, 255, 1)',
|
||||
'rgba(0, 67, 210, 1)'
|
||||
];
|
||||
|
||||
const series = response.data.map((item, index) => {
|
||||
// 为每个系列分配颜色,index 从 0 开始,依次对应 colors 数组
|
||||
const color = colors[index % colors.length]; // 使用取模确保不越界
|
||||
|
||||
return {
|
||||
name: item.lineName,
|
||||
type: 'bar',
|
||||
stack: 'Ad',
|
||||
barWidth: '20',
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
itemStyle: {
|
||||
color: color // 指定当前系列的颜色
|
||||
},
|
||||
data: [
|
||||
item.originalNgCount,
|
||||
item.edgeNgCount,
|
||||
item.silkNgCount,
|
||||
item.drillNgCount,
|
||||
item.coatingNgCount,
|
||||
item.packNgCount
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
this.loading = false;
|
||||
this.getChart(series);
|
||||
});
|
||||
},
|
||||
getChart(series) {
|
||||
var chartDom = document.getElementById('chart');
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option;
|
||||
option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: 30,
|
||||
top: 20,
|
||||
right: 30,
|
||||
bottom:20
|
||||
},
|
||||
legend: {},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: ['原片不良', '磨边不良', '丝印不良', '打孔不良', '镀膜不良', ' 钢包不良']
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value'
|
||||
}
|
||||
],
|
||||
series: series
|
||||
};
|
||||
|
||||
option && myChart.setOption(option);
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
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'
|
||||
}), '工段不良.xlsx')
|
||||
} catch (e) {
|
||||
if (typeof console !== 'undefined') console.log(e, exportTableOut)
|
||||
}
|
||||
return exportTableOut
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
/* 添加 scoped 以避免样式污染 */
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* 垂直排列 */
|
||||
gap: 20px;
|
||||
}
|
||||
.table-container,
|
||||
.chart-container {
|
||||
flex: 1;
|
||||
/* 让两个容器平分父容器的空间 */
|
||||
min-height: 300px;
|
||||
/* 设置最小高度,防止内容过少时变形 */
|
||||
border: 1px solid #ebeef5;
|
||||
/* 添加一个边框,方便看清分隔 */
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* 确保图表容器的父元素也有高度,ECharts 才能正确渲染 */
|
||||
.chart-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
305
src/views/quality/transmittanceTesting.vue
Normal file
305
src/views/quality/transmittanceTesting.vue
Normal file
@@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索工作栏 -->
|
||||
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" @headBtnClick="handleSearchBarBtnClick" />
|
||||
|
||||
<!-- 列表 -->
|
||||
<base-table :max-height="tableH" :table-props="tableProps" :page="queryParams.pageNo" :limit="queryParams.pageSize"
|
||||
:table-data="list" @emitFun="handleEmitFun">
|
||||
<!-- <method-btn v-if="tableBtn.length" slot="handleBtn" label="操作" :width="120" :method-list="tableBtn"
|
||||
@clickBtn="handleTableBtnClick" /> -->
|
||||
</base-table>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList" />
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { getPdList,} from '@/api/core/monitoring/auto';
|
||||
import { getFactoryPage } from '@/api/core/base/factory';
|
||||
import basicPageMixin from '@/mixins/lb/basicPageMixin';
|
||||
import { getTranslucentPage, exportTranslucent } from '@/api/monitoring/defectSummary';
|
||||
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
|
||||
export default {
|
||||
name: 'QualityInspectionType',
|
||||
mixins: [basicPageMixin, tableHeightMixin],
|
||||
data() {
|
||||
return {
|
||||
// tableBtn: [
|
||||
// this.$auth.hasPermi('base:quality-inspection-type:update')
|
||||
// ? {
|
||||
// type: 'edit',
|
||||
// btnName: '修改',
|
||||
// }
|
||||
// : undefined,
|
||||
// this.$auth.hasPermi('base:quality-inspection-type:delete')
|
||||
// ? {
|
||||
// type: 'delete',
|
||||
// btnName: '删除',
|
||||
// }
|
||||
// : undefined,
|
||||
// ].filter((v) => v),
|
||||
tableProps: [
|
||||
// {
|
||||
// prop: 'createTime',
|
||||
// label: '添加时间',
|
||||
// fixed: true,
|
||||
// width: 180,
|
||||
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
|
||||
// },
|
||||
{ prop: 'factoryName', label: '工厂' },
|
||||
{ prop: 'lineName', label: '产线' },
|
||||
{ prop: 'timeVal', label: '时间段' },
|
||||
{ prop: 'totalNum', label: '玻璃总数' },
|
||||
{ prop: 'goodNum', label: '一等品数量' },
|
||||
{ prop: 'passNum', label: '二等品数量' },
|
||||
{ prop: 'scrapNum', label: '废片数' },
|
||||
{ prop: 'passRate', label: '合格率' },
|
||||
],
|
||||
//
|
||||
searchBarFormConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '工厂',
|
||||
selectOptions: [],
|
||||
param: 'factoryId',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
param: 'lineId',
|
||||
},
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'datetimerange',
|
||||
format: 'yyyy-MM-dd HH:mm:ss',
|
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
width: 350
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
// {
|
||||
// type: 'button',
|
||||
// btnName: '重置',
|
||||
// name: 'reset',
|
||||
// },
|
||||
{
|
||||
type: 'separate',
|
||||
},
|
||||
// {
|
||||
// type: this.$auth.hasPermi('base:quality-inspection-type:create')
|
||||
// ? 'button'
|
||||
// : '',
|
||||
// btnName: '新增',
|
||||
// name: 'add',
|
||||
// plain: true,
|
||||
// color: 'success',
|
||||
// },
|
||||
{
|
||||
type: this.$auth.hasPermi('monitoring:translucent:export')
|
||||
? 'button'
|
||||
: '',
|
||||
btnName: '导出',
|
||||
name: 'export',
|
||||
color: 'warning',
|
||||
},
|
||||
],
|
||||
// 表单配置
|
||||
// formRows: [
|
||||
// [
|
||||
// {
|
||||
// input: true,
|
||||
// label: '检测类型名称',
|
||||
// prop: 'name',
|
||||
// rules: [{ required: true, message: '不能为空', trigger: 'blur' }],
|
||||
// // bind: {
|
||||
// // disabled: true, // some condition, like detail mode...
|
||||
// // }
|
||||
// },
|
||||
// ],
|
||||
// [{ input: true, label: '检测类型编码', prop: 'code' }],
|
||||
// [{ input: true, label: '备注', prop: 'remark' }],
|
||||
// ],
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
lineId: undefined,
|
||||
factoryId: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
};
|
||||
},
|
||||
// watch: {
|
||||
// form: {
|
||||
// handler: (val) => {
|
||||
// console.log('form changed', val);
|
||||
// },
|
||||
// deep: true
|
||||
// },
|
||||
// },
|
||||
created() {
|
||||
this.getList();
|
||||
this.getDict()
|
||||
},
|
||||
methods: {
|
||||
getDict() {
|
||||
getPdList().then(res => {
|
||||
this.searchBarFormConfig[1].selectOptions = res.data || [];
|
||||
});
|
||||
getFactoryPage({ pageSize: 100, pageNo: 1 }).then(res => {
|
||||
this.searchBarFormConfig[0].selectOptions = res.data.list || [];
|
||||
});
|
||||
},
|
||||
/** base table related */
|
||||
handleTableBtnClick({ data, type }) {
|
||||
switch (type) {
|
||||
case 'edit':
|
||||
this.handleUpdate(data);
|
||||
break;
|
||||
case 'delete':
|
||||
this.handleDelete(data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
/** search bar related */
|
||||
handleSearchBarBtnClick(btn) {
|
||||
console.log('btn',btn);
|
||||
|
||||
// const keys = ['name'];
|
||||
switch (btn.btnName) {
|
||||
case 'search':
|
||||
this.queryParams.lineId = btn.lineId ? btn.lineId : undefined
|
||||
this.queryParams.factoryId = btn.factoryId ? btn.factoryId : undefined
|
||||
this.queryParams.startTime = btn.timeVal ? btn.timeVal[0] : undefined
|
||||
this.queryParams.endTime = btn.timeVal ? btn.timeVal[1] : undefined
|
||||
// keys.forEach((key) => {
|
||||
// this.queryParams[key] = btn[key] || null;
|
||||
// });
|
||||
this.getList();
|
||||
break;
|
||||
case 'add':
|
||||
this.handleAdd();
|
||||
break;
|
||||
case 'export':
|
||||
this.handleExport();
|
||||
break;
|
||||
case 'reset':
|
||||
this.$refs['search-bar'].resetForm();
|
||||
this.resetQuery();
|
||||
break;
|
||||
}
|
||||
},
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 执行查询
|
||||
getTranslucentPage(this.queryParams).then((res) => {
|
||||
this.list = res.data.list ? res.data.list.map((item) => {
|
||||
const startTime = item.startTime ? moment(item.startTime).format('YYYY-MM-DD HH:mm:ss') : '';
|
||||
const endTime = item.endTime ? moment(item.endTime).format('YYYY-MM-DD HH:mm:ss') : '';
|
||||
|
||||
// 拼接开始时间和结束时间,中间用“至”连接
|
||||
const timeVal = startTime && endTime ? `${startTime} 至 ${endTime}` : '';
|
||||
|
||||
return {
|
||||
...item,
|
||||
timeVal: timeVal
|
||||
};
|
||||
}) :[]
|
||||
this.total = res.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 表单重置 */
|
||||
// reset() {
|
||||
// this.form = {
|
||||
// id: undefined,
|
||||
// name: undefined,
|
||||
// code: undefined,
|
||||
// remark: undefined,
|
||||
// };
|
||||
// this.resetForm('form');
|
||||
// },
|
||||
/** 新增按钮操作 */
|
||||
// handleAdd() {
|
||||
// this.reset();
|
||||
// this.open = true;
|
||||
// this.title = '添加质量检测类型基础';
|
||||
// },
|
||||
/** 修改按钮操作 */
|
||||
// handleUpdate(row) {
|
||||
// this.reset();
|
||||
// const id = row.id;
|
||||
// getQualityInspectionType(id).then((response) => {
|
||||
// this.form = response.data;
|
||||
// this.open = true;
|
||||
// this.title = '修改质量检测类型基础';
|
||||
// });
|
||||
// },
|
||||
/** 提交按钮 */
|
||||
// submitForm() {
|
||||
// // console.log('this.$refs.form', this.$refs.form);
|
||||
// // return;
|
||||
// this.$refs['form'].validate((valid) => {
|
||||
// if (!valid) {
|
||||
// return;
|
||||
// }
|
||||
// console.log('final form', JSON.stringify(this.form));
|
||||
// // 修改的提交
|
||||
// if (this.form.id != null) {
|
||||
// updateQualityInspectionType(this.form).then((response) => {
|
||||
// this.$modal.msgSuccess('修改成功');
|
||||
// this.open = false;
|
||||
// this.getList();
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// // 添加的提交
|
||||
// createQualityInspectionType(this.form).then((response) => {
|
||||
// this.$modal.msgSuccess('新增成功');
|
||||
// this.open = false;
|
||||
// this.getList();
|
||||
// });
|
||||
// });
|
||||
// },
|
||||
handleExport() {
|
||||
// 处理查询参数
|
||||
let params = { ...this.queryParams };
|
||||
// params.pageNo = undefined;
|
||||
// params.pageSize = undefined;
|
||||
this.$modal
|
||||
.confirm('是否确认导出透光率检测?')
|
||||
.then(() => {
|
||||
this.exportLoading = true;
|
||||
return exportTranslucent(params);
|
||||
})
|
||||
.then((response) => {
|
||||
this.$download.excel(response, '透光率检测.xls');
|
||||
this.exportLoading = false;
|
||||
})
|
||||
.catch(() => { });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user