生产
This commit is contained in:
6
.env.dev
6
.env.dev
@@ -12,8 +12,10 @@ ENV = 'development'
|
||||
VUE_APP_TITLE = 智能监控分析系统
|
||||
|
||||
# 芋道管理系统/开发环境
|
||||
# VUE_APP_BASE_API = 'http://192.168.8.22:48080'
|
||||
VUE_APP_BASE_API = 'http://172.16.33.65:48082'
|
||||
# VUE_APP_BASE_API = 'http://172.16.33.187:48082'
|
||||
# VUE_APP_BASE_API = 'http://line.kszny.picaiba.com'
|
||||
VUE_APP_BASE_API = 'http://172.16.32.79:48082'
|
||||
|
||||
|
||||
# 路由懒加载
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||
|
||||
@@ -59,3 +59,34 @@ export function getEquipmentAll() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getTree(query) {
|
||||
return request({
|
||||
url: '/base/factory/getTree',
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,3 +52,5 @@ export function exportEquipmentTypeExcel(query) {
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,6 +50,15 @@ export function getPdlAutoReportNewSearchNow(data) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getPdlAutoReportNewSearchLastGroup(data) {
|
||||
return request({
|
||||
url: '/monitoring/production-monitor/getPdlAutoReportNewSearchLastGroup',
|
||||
method: 'post',
|
||||
data: data,
|
||||
timeout: 60000,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 班组自动报表分页
|
||||
export function getTeamReportPage(data) {
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
63
src/api/monitoring/qualityIsra.js
Normal file
63
src/api/monitoring/qualityIsra.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* @Author: zhp
|
||||
* @Date: 2023-12-08 15:26:59
|
||||
* @LastEditTime: 2023-12-11 15:21:44
|
||||
* @LastEditors: zhp
|
||||
* @Description:
|
||||
*/
|
||||
import request from '@/utils/request'
|
||||
export function getQualityIsraPage(query) {
|
||||
return request({
|
||||
url: '/extend/check-isra-statistics/getIsraData',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
export function getQualityIsraDayMap(query) {
|
||||
return request({
|
||||
url: '/base/quality-isra-statistics/dayMap',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getQualityIsraWeekMap(query) {
|
||||
return request({
|
||||
url: '/base/quality-isra-statistics/weekMap',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getQualityIsraMonthMap(query) {
|
||||
return request({
|
||||
url: '/base/quality-isra-statistics/monthMap',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getQualityIsraDayList(query) {
|
||||
return request({
|
||||
url: '/base/quality-isra-statistics/dayList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getQualityIsraWeekList(query) {
|
||||
return request({
|
||||
url: '/base/quality-isra-statistics/weekList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getQualityIsraMonthList(query) {
|
||||
return request({
|
||||
url: '/base/quality-isra-statistics/monthList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
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 |
@@ -6,104 +6,48 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="form"
|
||||
:label-width="`${labelWidth}px`"
|
||||
:size="size"
|
||||
:label-position="labelPosition"
|
||||
v-loading="formLoading">
|
||||
<el-row :gutter="20" v-for="(row, rindex) in rows" :key="rindex">
|
||||
<el-col v-for="col in row" :key="col.label" :span="24 / row.length">
|
||||
<el-form-item :label="col.label" :prop="col.prop" :rules="col.rules">
|
||||
<el-input
|
||||
v-if="col.input"
|
||||
v-model="form[col.prop]"
|
||||
@change="$emit('update', form)"
|
||||
:placeholder="`请输入${col.label}`"
|
||||
v-bind="col.bind" />
|
||||
<el-input
|
||||
v-if="col.textarea"
|
||||
type="textarea"
|
||||
v-model="form[col.prop]"
|
||||
@change="$emit('update', form)"
|
||||
:placeholder="`请输入${col.label}`"
|
||||
v-bind="col.bind" />
|
||||
<el-select
|
||||
v-if="col.select"
|
||||
v-model="form[col.prop]"
|
||||
:placeholder="`请选择${col.label}`"
|
||||
@change="$emit('update', form)"
|
||||
v-bind="col.bind">
|
||||
<el-option
|
||||
v-for="opt in optionListOf[col.prop]"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value" />
|
||||
</el-select>
|
||||
<el-date-picker
|
||||
v-if="col.datetime"
|
||||
v-model="form[col.prop]"
|
||||
type="datetime"
|
||||
:placeholder="`请选择${col.label}`"
|
||||
value-format="timestamp"
|
||||
v-bind="col.bind"></el-date-picker>
|
||||
<el-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-form ref="form" :model="form" :label-width="`${labelWidth}px`" :size="size" :label-position="labelPosition"
|
||||
v-loading="formLoading">
|
||||
<el-row :gutter="20" v-for="(row, rindex) in rows" :key="rindex">
|
||||
<el-col v-for="col in row" :key="col.label" :span="24 / row.length">
|
||||
<el-form-item :label="col.label" :prop="col.prop" :rules="col.rules">
|
||||
<el-input v-if="col.input" v-model="form[col.prop]" @change="$emit('update', form)"
|
||||
:placeholder="`请输入${col.label}`" v-bind="col.bind" />
|
||||
<el-input v-if="col.textarea" type="textarea" v-model="form[col.prop]" @change="$emit('update', form)"
|
||||
:placeholder="`请输入${col.label}`" v-bind="col.bind" />
|
||||
<el-select v-if="col.select" v-model="form[col.prop]" :placeholder="`请选择${col.label}`"
|
||||
@change="$emit('update', form)" v-bind="col.bind">
|
||||
<el-option v-for="opt in optionListOf[col.prop]" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
<el-date-picker v-if="col.datetime" v-model="form[col.prop]" type="datetime" :placeholder="`请选择${col.label}`"
|
||||
value-format="timestamp" v-bind="col.bind"></el-date-picker>
|
||||
<el-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">
|
||||
<span class="close-icon" :class="uploadOpen ? 'open' : ''">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-arrow-right"
|
||||
@click="handleFilesOpen" />
|
||||
</span>
|
||||
<!-- :file-list="uploadedFileList" -->
|
||||
<el-upload
|
||||
class="upload-in-dialog"
|
||||
v-if="col.upload"
|
||||
:action="uploadUrl"
|
||||
:headers="uploadHeaders"
|
||||
:show-file-list="false"
|
||||
icon="el-icon-upload2"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="handleUploadSuccess"
|
||||
v-bind="col.bind">
|
||||
<el-button size="mini" :disabled="col.bind?.disabled || false">
|
||||
<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)" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div class="upload-area" :class="uploadOpen ? '' : 'height-48'" ref="uploadArea" v-if="col.upload">
|
||||
<span class="close-icon" :class="uploadOpen ? 'open' : ''">
|
||||
<el-button type="text" icon="el-icon-arrow-right" @click="handleFilesOpen" />
|
||||
</span>
|
||||
<!-- :file-list="uploadedFileList" -->
|
||||
<el-upload class="upload-in-dialog" v-if="col.upload" :action="uploadUrl" :headers="uploadHeaders"
|
||||
:show-file-list="false" icon="el-icon-upload2" :before-upload="beforeUpload"
|
||||
:on-success="handleUploadSuccess" v-bind="col.bind">
|
||||
<el-button size="mini" :disabled="col.bind?.disabled || false">
|
||||
<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)" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -134,7 +78,8 @@ const uploadedFile = {
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
methods: {
|
||||
|
||||
handleDelete() {
|
||||
this.$emit('delete', this.file);
|
||||
},
|
||||
@@ -251,7 +196,12 @@ export default {
|
||||
// 处理 options
|
||||
this.handleOptions();
|
||||
},
|
||||
methods: {
|
||||
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);
|
||||
|
||||
@@ -6,35 +6,27 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<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')
|
||||
? '详情'
|
||||
: mode.includes('edit')
|
||||
? '编辑'
|
||||
: '新增'
|
||||
}}
|
||||
</SmallTitle>
|
||||
<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')
|
||||
? '详情'
|
||||
: mode.includes('edit')
|
||||
? '编辑'
|
||||
: '新增'
|
||||
}}
|
||||
</SmallTitle>
|
||||
|
||||
<div class="drawer-body flex">
|
||||
<div class="drawer-body__content">
|
||||
<section v-for="(section, index) in sections" :key="section.key">
|
||||
<SmallTitle v-if="index != 0">{{ section.name }}</SmallTitle>
|
||||
<div class="drawer-body flex">
|
||||
<div class="drawer-body__content">
|
||||
<section v-for="(section, index) in sections" :key="section.key">
|
||||
<SmallTitle v-if="index != 0">{{ section.name }}</SmallTitle>
|
||||
|
||||
<div
|
||||
class="form-part"
|
||||
v-if="section.key == 'base'"
|
||||
style="border-bottom: 1px solid #dfdfdf; margin-bottom: 24px">
|
||||
<el-skeleton v-if="!showForm" animated />
|
||||
<!-- <BaseInfoForm
|
||||
<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
|
||||
key="drawer-dialog-form"
|
||||
v-if="showForm"
|
||||
ref="form"
|
||||
@@ -42,141 +34,87 @@
|
||||
v-model="form"
|
||||
:rows="formRows" /> -->
|
||||
|
||||
<!-- 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>
|
||||
<div class="value" style="font-size: 14px">
|
||||
{{ form.equipmentName }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div
|
||||
class="title"
|
||||
style="font-weight: 700; font-size: 16px; margin: 8px 0">
|
||||
关联表名
|
||||
</div>
|
||||
<div class="value" style="font-size: 14px">
|
||||
{{ form.plcName }}
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- else -->
|
||||
<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-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"
|
||||
:value="plc.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- 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>
|
||||
<div class="value" style="font-size: 14px">
|
||||
{{ form.equipmentName }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="title" style="font-weight: 700; font-size: 16px; margin: 8px 0">
|
||||
关联表名
|
||||
</div>
|
||||
<div class="value" style="font-size: 14px">
|
||||
{{ form.plcName }}
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- else -->
|
||||
<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-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"
|
||||
:value="plc.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form>
|
||||
</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">
|
||||
<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">
|
||||
<!-- :add-button-show="mode.includes('detail') ? null : '添加属性'"
|
||||
<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">
|
||||
<!-- :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" />
|
||||
</base-table>
|
||||
<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" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<!-- 分页组件 -->
|
||||
<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>
|
||||
</div>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 属性对话框 -->
|
||||
<base-dialog
|
||||
v-if="sections[1].allowAdd"
|
||||
:dialogTitle="attrTitle"
|
||||
:dialogVisible="attrFormVisible"
|
||||
width="45%"
|
||||
:append-to-body="true"
|
||||
custom-class="baseDialog"
|
||||
@close="closeAttrForm"
|
||||
@cancel="closeAttrForm"
|
||||
@confirm="submitAttrForm">
|
||||
<!-- :disabled="mode.includes('detail')" -->
|
||||
<DialogForm
|
||||
v-if="attrFormVisible"
|
||||
ref="attrForm"
|
||||
v-model="attrForm"
|
||||
:rows="attrRows" />
|
||||
</base-dialog>
|
||||
</el-drawer>
|
||||
<!-- 属性对话框 -->
|
||||
<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" :data-form="attrForm"
|
||||
:rows="attrRows"
|
||||
@update="handleAttrFormUpdate"/>
|
||||
</base-dialog>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -232,7 +170,9 @@ export default {
|
||||
defaultValue: '',
|
||||
description: '',
|
||||
remark: '',
|
||||
alarmContent: '',
|
||||
alarmContent: '',
|
||||
displayTip: false,
|
||||
alarmTip: false,
|
||||
},
|
||||
attrFormVisible: false,
|
||||
attrRows: [
|
||||
@@ -342,7 +282,27 @@ 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,
|
||||
@@ -436,7 +396,24 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
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':
|
||||
@@ -502,7 +479,8 @@ export default {
|
||||
name: '',
|
||||
plcParamName: '',
|
||||
unit: '',
|
||||
collection: 1,
|
||||
collection: 1,
|
||||
|
||||
minValue: '',
|
||||
maxValue: '',
|
||||
defaultValue: '',
|
||||
@@ -510,7 +488,9 @@ export default {
|
||||
remark: '',
|
||||
equipmentParamType: '',
|
||||
productionParamType: '',
|
||||
alarmContent: '',
|
||||
alarmContent: '',
|
||||
displayTip: false,
|
||||
alarmTip: false,
|
||||
};
|
||||
this.attrTitle = '添加参数绑定信息';
|
||||
this.attrFormVisible = true;
|
||||
@@ -523,8 +503,15 @@ export default {
|
||||
method: 'get',
|
||||
params: { id: attrId },
|
||||
});
|
||||
if (res.code == 0) {
|
||||
this.attrForm = res.data;
|
||||
if (res.code == 0) {
|
||||
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;
|
||||
}
|
||||
@@ -563,7 +550,8 @@ export default {
|
||||
this.$refs['attrForm'].validate(async (valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.log('this.attrForm', this.attrForm);
|
||||
|
||||
const isEdit = this.attrForm.id != null;
|
||||
this.attrFormSubmitting = true;
|
||||
@@ -583,8 +571,9 @@ export default {
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
onClose: () => {
|
||||
this.getAttrList();
|
||||
this.shouldRefreshPageView = true;
|
||||
this.shouldRefreshPageView = true;
|
||||
this.getAttrList();
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ export default {
|
||||
id: null,
|
||||
code: '',
|
||||
materialId: '',
|
||||
price: '',
|
||||
price: undefined,
|
||||
startTime: new Date().getTime(),
|
||||
endTime: null,
|
||||
remark: '',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -72,16 +72,6 @@ export default {
|
||||
dateLabelList: [],
|
||||
optionArrUrl: [getProductionLinePage],
|
||||
formConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
param: 'lineIds',
|
||||
defaultSelect: [],
|
||||
multiple: true,
|
||||
filterable: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '时间',
|
||||
@@ -92,7 +82,17 @@ export default {
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'time',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
param: 'lineIds',
|
||||
defaultSelect: [],
|
||||
multiple: true,
|
||||
filterable: true,
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
@@ -113,7 +113,7 @@ export default {
|
||||
};
|
||||
this.optionArrUrl.forEach((item, index) => {
|
||||
item(params).then((response) => {
|
||||
this.formConfig[index].selectOptions = response.data.list;
|
||||
this.formConfig[1].selectOptions = response.data.list;
|
||||
// this.formConfig[0].defaultSelect = response.data.list[0].id
|
||||
// this.$set(this.formConfig[0], 'defaultSelect', response.data.list[0].id)
|
||||
});
|
||||
|
||||
@@ -279,7 +279,8 @@ export default {
|
||||
filterable: true,
|
||||
clearable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// {
|
||||
// select: true,
|
||||
// label: '设备分组',
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -66,16 +66,15 @@
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完成单位产品用时" prop="processTime">
|
||||
<el-input :disabled="isdetail" v-model="dataForm.processTime" placeholder="请输入完成单位产品用时" />
|
||||
<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="processType">
|
||||
<el-select v-model="dataForm.processType" clearable style="width: 100%" :disabled="isdetail"
|
||||
placeholder="请选择加工属性">
|
||||
<el-option v-for="dict in processTypeList" :key="dict.id" :label="dict.label"
|
||||
:value="dict.id" />
|
||||
<el-form-item label=" 产品工艺" prop="processType">
|
||||
<el-select multiple v-model="dataForm.processType" clearable style="width: 100%" :disabled="isdetail"
|
||||
placeholder="请选择产品工艺">
|
||||
<el-option v-for="dict in processTypeList" :key="dict.id" :label="dict.label" :value="dict.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
@@ -1,139 +1,142 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="visible"
|
||||
:width="'35%'"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
class="dialog">
|
||||
<template #title>
|
||||
<slot name="title">
|
||||
<div class="titleStyle">
|
||||
{{ !dataForm.id ? '新增' : '编辑' }}
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
<el-dialog v-loading="isLoading" loading-text="处理中..." loading-spinner="el-icon-loading"
|
||||
loading-background="rgba(255, 255, 255, 0.7)" :visible.sync="visible" :width="'35%'" :append-to-body="true"
|
||||
:close-on-click-modal="false" class="dialog">
|
||||
<template #title>
|
||||
<slot name="title">
|
||||
<div class="titleStyle">
|
||||
{{ !dataForm.id ? '新增' : '编辑' }}
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<el-form
|
||||
ref="dataForm"
|
||||
:model="dataForm"
|
||||
:rules="dataRule"
|
||||
label-width="100px"
|
||||
@keyup.enter.native="dataFormSubmit()">
|
||||
<el-form-item label="属性名" prop="name">
|
||||
<el-input
|
||||
v-model="dataForm.name"
|
||||
placeholder="请输入属性名"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="属性值" prop="value">
|
||||
<el-input
|
||||
v-model="dataForm.value"
|
||||
placeholder="请输入属性值"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form ref="dataForm" :model="dataForm" :rules="dataRule" label-width="100px"
|
||||
@keyup.enter.native="dataFormSubmit()">
|
||||
<el-form-item label="属性名" prop="name">
|
||||
<el-input v-model="dataForm.name" placeholder="请输入属性名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="属性值" prop="value">
|
||||
<el-input v-model="dataForm.value" placeholder="请输入属性值" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row style="text-align: right">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="dataFormSubmit()">确定</el-button>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
<el-row style="text-align: right">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button :loading="isLoading" type="primary" @click="dataFormSubmit()">确定</el-button>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
createProductAttr,
|
||||
updateProductAttr,
|
||||
getProductAttr,
|
||||
createProductAttr,
|
||||
updateProductAttr,
|
||||
getProductAttr,
|
||||
} from '@/api/core/base/productAttr';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
productId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
dataForm: {
|
||||
id: 0,
|
||||
name: '',
|
||||
value: '',
|
||||
},
|
||||
dataRule: {
|
||||
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init(id) {
|
||||
this.dataForm.id = id || '';
|
||||
this.visible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].resetFields();
|
||||
if (this.dataForm.id) {
|
||||
getProductAttr(this.dataForm.id).then((res) => {
|
||||
const { name, value } = res.data;
|
||||
this.dataForm.name = name;
|
||||
this.dataForm.value = value;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 表单提交
|
||||
dataFormSubmit() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
// 修改的提交
|
||||
if (this.dataForm.id) {
|
||||
updateProductAttr({
|
||||
...this.dataForm,
|
||||
productId: this.productId,
|
||||
}).then((response) => {
|
||||
this.$modal.msgSuccess('修改成功');
|
||||
this.visible = false;
|
||||
this.$emit('refreshDataList');
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 添加的提交
|
||||
createProductAttr({
|
||||
...this.dataForm,
|
||||
productId: this.productId,
|
||||
}).then((response) => {
|
||||
this.$modal.msgSuccess('新增成功');
|
||||
this.visible = false;
|
||||
this.$emit('refreshDataList');
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
props: {
|
||||
productId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
isLoading: false,
|
||||
dataForm: {
|
||||
id: 0,
|
||||
name: '',
|
||||
value: '',
|
||||
},
|
||||
dataRule: {
|
||||
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init(id) {
|
||||
this.dataForm.id = id || '';
|
||||
this.visible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].resetFields();
|
||||
if (this.dataForm.id) {
|
||||
getProductAttr(this.dataForm.id).then((res) => {
|
||||
const { name, value } = res.data;
|
||||
this.dataForm.name = name;
|
||||
this.dataForm.value = value;
|
||||
}).catch(err => {
|
||||
console.error('获取属性详情失败:', err);
|
||||
this.$modal.msgError('获取数据失败,请重试');
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 表单提交(优化加载状态和错误处理)
|
||||
async dataFormSubmit() {
|
||||
// 先验证表单
|
||||
const valid = await new Promise((resolve) => {
|
||||
this.$refs['dataForm'].validate((isValid) => resolve(isValid));
|
||||
});
|
||||
|
||||
if (!valid) return;
|
||||
|
||||
this.isLoading = true; // 开始加载
|
||||
|
||||
try {
|
||||
if (this.dataForm.id) {
|
||||
// 编辑操作
|
||||
await updateProductAttr({
|
||||
...this.dataForm,
|
||||
productId: this.productId,
|
||||
});
|
||||
this.$modal.msgSuccess('修改成功');
|
||||
} else {
|
||||
// 新增操作
|
||||
await createProductAttr({
|
||||
...this.dataForm,
|
||||
productId: this.productId,
|
||||
});
|
||||
this.$modal.msgSuccess('新增成功');
|
||||
}
|
||||
this.visible = false;
|
||||
this.$emit('refreshDataList');
|
||||
} catch (error) {
|
||||
// 错误处理
|
||||
console.error('提交失败:', error);
|
||||
this.$modal.msgError('操作失败,请重试');
|
||||
} finally {
|
||||
// 无论成功失败,都关闭加载状态
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dialog >>> .el-dialog__body {
|
||||
padding: 30px 24px;
|
||||
.dialog>>>.el-dialog__body {
|
||||
padding: 30px 24px;
|
||||
}
|
||||
.dialog >>> .el-dialog__header {
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-weight: 500;
|
||||
padding: 13px 24px;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
|
||||
.dialog>>>.el-dialog__header {
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-weight: 500;
|
||||
padding: 13px 24px;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
}
|
||||
.dialog >>> .el-dialog__header .titleStyle::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #0b58ff;
|
||||
border-radius: 1px;
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
|
||||
.dialog>>>.el-dialog__header .titleStyle::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #0b58ff;
|
||||
border-radius: 1px;
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -262,6 +262,14 @@ export default {
|
||||
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),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<el-tabs v-model="activeLabel" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'全部数据'" name="table">
|
||||
<base-table-s ref="lineCurrentShiftTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'"
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData" :max-height="210" />
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData" :max-height="300" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000当天生产折线图\u3000'" name="graph">
|
||||
<div style="height: 230px;" v-if="activeLabel == 'graph'" class="graph">
|
||||
@@ -57,7 +57,7 @@
|
||||
<el-tabs v-model="activeLabelDay" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'全部数据'" name="table">
|
||||
<base-table-s ref="lineTodayTable" style="margin-bottom: 16px;" v-if="activeLabelDay == 'table'"
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData2" :max-height="210" />
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData2" :max-height="300" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000当天生产折线图\u3000'" name="graph">
|
||||
<div style="height: 230px;" v-if="activeLabelDay == 'graph'" class="graph">
|
||||
@@ -71,9 +71,55 @@
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-inner" v-if="listQuery.timeType === 3">
|
||||
<!-- 当班数据(占1/2剩余高度) -->
|
||||
<div class="content-card energyOverlimitLog">
|
||||
<span class="blue-block"></span>
|
||||
<span class="tip">上一班数据</span>
|
||||
<el-row style="margin-top: 10px;">
|
||||
<el-col class="custom-tabs">
|
||||
<el-tabs v-model="activeLabel" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'全部数据'" name="table">
|
||||
<base-table-s ref="lineCurrentShiftTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'"
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData" :max-height="300" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000当天生产折线图\u3000'" name="graph">
|
||||
<div style="height: 230px;" v-if="activeLabel == 'graph'" class="graph">
|
||||
<barChart v-if="tableData && tableData.length > 0" ref="barChart" height="230px"
|
||||
:bar-data="tableData" />
|
||||
<div v-else class="no-data-bg"></div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 当天数据(占1/2剩余高度) -->
|
||||
<div class="content-card energyOverlimitLog">
|
||||
<span class="blue-block"></span>
|
||||
<span class="tip">当天数据</span>
|
||||
<el-row style="margin-top: 10px;">
|
||||
<el-col class="custom-tabs">
|
||||
<el-tabs v-model="activeLabelDay" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'全部数据'" name="table">
|
||||
<base-table-s ref="lineTodayTable" style="margin-bottom: 16px;" v-if="activeLabelDay == 'table'"
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData2" :max-height="300" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000当天生产折线图\u3000'" name="graph">
|
||||
<div style="height: 230px;" v-if="activeLabelDay == 'graph'" class="graph">
|
||||
<barChart v-if="tableData2 && tableData2.length > 0" ref="barChart" height="230px"
|
||||
:bar-data="tableData2" />
|
||||
<div v-else class="no-data-bg"></div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 3.2 时间维度为“自定义”时的内容(两个平分高度的div) -->
|
||||
<div class="content-inner" v-else>
|
||||
<div class="content-inner" v-if="listQuery.timeType === 2">
|
||||
<div class="content-card energyOverlimitLog">
|
||||
<span class="blue-block"></span>
|
||||
<span class="tip" v-if="listQuery.startTime && listQuery.endTime">
|
||||
@@ -86,7 +132,7 @@
|
||||
<span class="tip" v-else>生产表格数据 </span>
|
||||
<div class="graph">
|
||||
<base-table-s ref="lineCustomTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'" :page="1"
|
||||
:limit="100" :table-props="tableProps" :max-height="210" :table-data="tableDataCustom" />
|
||||
:limit="100" :table-props="tableProps" :max-height="300" :table-data="tableDataCustom" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -113,7 +159,7 @@
|
||||
<span class="tip">当班数据</span>
|
||||
<base-table-s ref="productCurrentShiftTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'"
|
||||
:page="1" :limit="100" :table-props="productTableProps" :table-data="productTableData"
|
||||
:max-height="210" />
|
||||
:max-height="300" />
|
||||
</div>
|
||||
|
||||
<!-- 当天数据(占1/2剩余高度) -->
|
||||
@@ -122,7 +168,7 @@
|
||||
<span class="tip">当天数据</span>
|
||||
<base-table-s ref="productTodayTable" style="margin-bottom: 16px;" v-if="activeLabelDay == 'table'"
|
||||
:page="1" :limit="100" :table-props="productTablePropsDay" :table-data="productTableDataDay"
|
||||
:max-height="210" />
|
||||
:max-height="300" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -142,7 +188,7 @@
|
||||
</span>
|
||||
<span class="tip" v-else>生产表格数据 </span>
|
||||
<base-table-s ref="productCustomTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'" :page="1"
|
||||
:limit="100" :table-props="productTableProps" :table-data="productTableData" :max-height="210" />
|
||||
:limit="100" :table-props="productTableProps" :table-data="productTableData" :max-height="300" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,7 +200,7 @@
|
||||
import { parseTime } from '@/filter/code-filter';
|
||||
import {
|
||||
getLineAuto, getPdList, getPdlAutoReportNewSearchNow, getProductAuto,
|
||||
getProcessAutoReportGroup, getProcessAutoReportDay, getProcessAutoReportNew
|
||||
getProcessAutoReportGroup, getProcessAutoReportDay, getProcessAutoReportNew, getPdlAutoReportNewSearchLastGroup
|
||||
} from '@/api/core/monitoring/auto';
|
||||
import { getFactoryPage } from '@/api/core/base/factory';
|
||||
import * as XLSX from 'xlsx';
|
||||
@@ -165,11 +211,11 @@ import ButtonNav from '@/components/ButtonNav';
|
||||
import { listData } from '@/api/system/dict/data';
|
||||
// 表格列配置
|
||||
const tableProps = [
|
||||
// {
|
||||
// prop: 'factoryName',
|
||||
// label: '工厂',
|
||||
// fixed: true
|
||||
// },
|
||||
{
|
||||
prop: 'factoryName',
|
||||
label: '工厂',
|
||||
fixed: true
|
||||
},
|
||||
{
|
||||
prop: 'lineName',
|
||||
label: '产线',
|
||||
@@ -368,15 +414,27 @@ export default {
|
||||
productTableDataDay: [],
|
||||
tableDataCustom: [],
|
||||
list: [], // 折线图数据
|
||||
timeTypeOptions: {
|
||||
productLine: [ // 按产线监控(包含上一班)
|
||||
{ id: 1, name: '当天' },
|
||||
{ id: 2, name: '自定义' },
|
||||
{ id: 3, name: '上一班' }
|
||||
],
|
||||
product: [ // 按产品监控(不含上一班)
|
||||
{ id: 1, name: '当天' },
|
||||
{ id: 2, name: '自定义' }
|
||||
]
|
||||
},
|
||||
formConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '时间维度',
|
||||
selectOptions: [
|
||||
{ id: 1, name: '当天' },
|
||||
{ id: 2, name: '自定义' }
|
||||
{ id: 2, name: '自定义' },
|
||||
{ id: 3, name: '上一班' }
|
||||
],
|
||||
width: 80,
|
||||
width: 100,
|
||||
onchange: true,
|
||||
// defaultSelect: 1,
|
||||
clearable: false,
|
||||
@@ -437,6 +495,7 @@ export default {
|
||||
{ id: 3, name: '月' },
|
||||
{ id: 4, name: '年' }
|
||||
],
|
||||
onchange: true,
|
||||
width: 80,
|
||||
param: 'reportType'
|
||||
},
|
||||
@@ -467,6 +526,13 @@ export default {
|
||||
productTableProps() {
|
||||
// 当班数据的完整表头(基础列 + 当班动态表头)
|
||||
const baseColumns = [
|
||||
{
|
||||
prop: 'sizes',
|
||||
label: '规格',
|
||||
width: 105,
|
||||
showOverflowtooltip: true,
|
||||
fixed: true
|
||||
},
|
||||
{
|
||||
prop: 'process',
|
||||
label: '产品工艺',
|
||||
@@ -476,7 +542,8 @@ export default {
|
||||
prop: 'processType',
|
||||
label: '产品类型',
|
||||
filter: (val) => (val != 1 ? '面板' : '背板'),
|
||||
fixed: true
|
||||
fixed: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
prop: 'factoryName',
|
||||
@@ -513,13 +580,16 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.buttonNav) {
|
||||
this.$refs.buttonNav.currentMenu = '按产线监控';
|
||||
this.formConfig[0].selectOptions = this.timeTypeOptions.productLine;
|
||||
}
|
||||
if (this.$refs.searchBarForm) {
|
||||
// this.$refs.searchBarForm.formInline.timeVal = [
|
||||
// yesterday.getTime(),
|
||||
// end.getTime()
|
||||
// ];
|
||||
|
||||
this.$refs.searchBarForm.formInline.timeType = 1
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -576,18 +646,26 @@ export default {
|
||||
|
||||
// 3. 执行公共重置
|
||||
resetCommon();
|
||||
|
||||
// if (this.activeName === 'productLine') {
|
||||
// } else {
|
||||
// }
|
||||
// 4. 根据类型设置差异化的表单配置(仅处理不同的部分)
|
||||
if (isProductLine) {
|
||||
// 按产线监控:显示产线,隐藏产品工艺和类型
|
||||
// 按产线监控:显示产线,隐藏产品工艺和类型,时间维度包含上一班
|
||||
this.formConfig[0].selectOptions = this.timeTypeOptions.productLine; // 恢复上一班选项
|
||||
this.formConfig[3].type = 'select'; // 显示产线
|
||||
this.formConfig[4].type = ''; // 隐藏产品工艺
|
||||
this.formConfig[5].type = ''; // 隐藏产品类型
|
||||
this.getDayDataList();
|
||||
|
||||
} else {
|
||||
// 按产品监控:显示产品工艺和类型,隐藏产线
|
||||
// 按产品监控:显示产品工艺和类型,隐藏产线,时间维度移除上一班
|
||||
this.formConfig[0].selectOptions = this.timeTypeOptions.product; // 不含上一班
|
||||
this.formConfig[3].type = ''; // 隐藏产线
|
||||
this.formConfig[4].type = 'select'; // 显示产品工艺
|
||||
this.formConfig[5].type = 'select'; // 显示产品类型
|
||||
this.getProductList();
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
@@ -601,6 +679,12 @@ export default {
|
||||
{ ref: 'lineCurrentShiftTable', name: '产线监控_当班数据' },
|
||||
{ ref: 'lineTodayTable', name: '产线监控_当天数据' }
|
||||
], '产线监控_当班及当天数据汇总'); // 传入自定义汇总文件名
|
||||
} else if (this.listQuery.timeType === 1) {
|
||||
// 产线-当天:导出当班 + 当天两个表格(自定义汇总文件名)
|
||||
this.exportMultipleTables([
|
||||
{ ref: 'lineCurrentShiftTable', name: '产线监控_上一班数据' },
|
||||
{ ref: 'lineTodayTable', name: '产线监控_当天数据' }
|
||||
], '产线监控_当班及当天数据汇总'); // 传入自定义汇总文件名
|
||||
} else {
|
||||
// 产线-自定义:导出一个表格(自定义文件名)
|
||||
this.exportSingleTable('lineCustomTable', '产线监控_自定义时间数据');
|
||||
@@ -801,31 +885,126 @@ export default {
|
||||
this.formConfig[2].selectOptions = res.data.list || [];
|
||||
});
|
||||
},
|
||||
getWeekTimeRange(date) {
|
||||
const targetDate = new Date(date);
|
||||
const day = targetDate.getDay() || 7; // 周日转为7
|
||||
const year = targetDate.getFullYear();
|
||||
const month = targetDate.getMonth();
|
||||
const dateNum = targetDate.getDate();
|
||||
|
||||
// 本周一 00:00:00
|
||||
const startDate = new Date(year, month, dateNum - day + 1);
|
||||
startDate.setHours(0, 0, 0, 0);
|
||||
|
||||
// 本周日 23:59:59
|
||||
const endDate = new Date(year, month, dateNum - day + 7);
|
||||
endDate.setHours(23, 59, 59, 999);
|
||||
|
||||
return {
|
||||
startTime: startDate.getTime(),
|
||||
endTime: endDate.getTime()
|
||||
};
|
||||
},
|
||||
|
||||
// 辅助函数:获取本年的开始和结束时间戳(1月1日00:00:00 到 12月31日23:59:59)
|
||||
getYearTimeRange(date) {
|
||||
const targetDate = new Date(date);
|
||||
const year = targetDate.getFullYear();
|
||||
|
||||
// 本年1月1日 00:00:00
|
||||
const startDate = new Date(year, 0, 1);
|
||||
startDate.setHours(0, 0, 0, 0);
|
||||
|
||||
// 本年12月31日 23:59:59
|
||||
const endDate = new Date(year, 11, 31);
|
||||
endDate.setHours(23, 59, 59, 999);
|
||||
|
||||
return {
|
||||
startTime: startDate.getTime(),
|
||||
endTime: endDate.getTime()
|
||||
};
|
||||
},
|
||||
// 搜索/导出按钮点击
|
||||
buttonClick(val) {
|
||||
if (this.activeName === 'productLine') {
|
||||
this.listQuery.pageNo = 1;
|
||||
this.listQuery.pageSize = 10;
|
||||
this.listQuery.factoryId = val.factoryId || undefined;
|
||||
this.listQuery.process = val.process ? val.process : [];
|
||||
this.listQuery.lineId = val.lineId ? val.lineId : [];
|
||||
this.listQuery.processType = val.processType ? val.processType : [];
|
||||
this.listQuery.reportType = val.reportType || undefined;
|
||||
this.listQuery.timeType = val.timeType || undefined;
|
||||
this.listQuery.searchType = val.searchType || undefined;
|
||||
|
||||
// 处理不同时间选择类型
|
||||
if (val.timeVal) {
|
||||
this.listQuery.startTime = val.timeVal[0];
|
||||
this.listQuery.endTime = val.timeVal[1];
|
||||
} else if (val.timeValWeek) {
|
||||
// 周选择器
|
||||
const { startTime, endTime } = this.getWeekTimeRange(val.timeValWeek);
|
||||
this.listQuery.startTime = startTime;
|
||||
this.listQuery.endTime = endTime;
|
||||
} else if (val.timeValMonth) {
|
||||
// 月选择器
|
||||
this.listQuery.startTime = val.timeValMonth[0];
|
||||
this.listQuery.endTime = val.timeValMonth[1];
|
||||
} else if (val.timeValYear) {
|
||||
// 年选择器
|
||||
const { startTime, endTime } = this.getYearTimeRange(val.timeValYear);
|
||||
this.listQuery.startTime = startTime;
|
||||
this.listQuery.endTime = endTime;
|
||||
} else {
|
||||
this.listQuery.startTime = undefined;
|
||||
this.listQuery.endTime = undefined;
|
||||
}
|
||||
} else {
|
||||
this.listQuery.pageNo = 1;
|
||||
this.listQuery.pageSize = 10;
|
||||
this.listQuery.factoryId = val.factoryId || []
|
||||
this.listQuery.process = val.process ? val.process : [];
|
||||
this.listQuery.lineId = undefined;
|
||||
this.listQuery.processType = val.processType ? val.processType : [];
|
||||
this.listQuery.reportType = val.reportType || undefined;
|
||||
this.listQuery.timeType = val.timeType || undefined;
|
||||
this.listQuery.searchType = val.searchType || undefined;
|
||||
|
||||
// 处理不同时间选择类型
|
||||
if (val.timeVal) {
|
||||
this.listQuery.startTime = val.timeVal[0];
|
||||
this.listQuery.endTime = val.timeVal[1];
|
||||
} else if (val.timeValWeek) {
|
||||
// 周选择器
|
||||
const { startTime, endTime } = this.getWeekTimeRange(val.timeValWeek);
|
||||
this.listQuery.startTime = startTime;
|
||||
this.listQuery.endTime = endTime;
|
||||
} else if (val.timeValMonth) {
|
||||
// 月选择器
|
||||
this.listQuery.startTime = val.timeValMonth[0];
|
||||
this.listQuery.endTime = val.timeValMonth[1];
|
||||
} else if (val.timeValYear) {
|
||||
// 年选择器
|
||||
const { startTime, endTime } = this.getYearTimeRange(val.timeValYear);
|
||||
this.listQuery.startTime = startTime;
|
||||
this.listQuery.endTime = endTime;
|
||||
} else {
|
||||
this.listQuery.startTime = undefined;
|
||||
this.listQuery.endTime = undefined;
|
||||
}
|
||||
}
|
||||
switch (val.btnName) {
|
||||
case 'search':
|
||||
this.listQuery.pageNo = 1;
|
||||
this.listQuery.pageSize = 10;
|
||||
this.listQuery.factoryId = val.factoryId || undefined;
|
||||
this.listQuery.process = val.process ? val.process : [];
|
||||
this.listQuery.lineId = val.lineId ? val.lineId : [];
|
||||
this.listQuery.processType = val.processType ? val.processType : [];
|
||||
this.listQuery.reportType = val.reportType || undefined;
|
||||
this.listQuery.timeType = val.timeType || undefined;
|
||||
this.listQuery.searchType = val.searchType || undefined;
|
||||
this.listQuery.startTime = val.timeVal ? val.timeVal[0] : undefined;
|
||||
this.listQuery.endTime = val.timeVal ? val.timeVal[1] : undefined;
|
||||
if (this.activeName === 'productLine') {
|
||||
if (this.listQuery.timeType === 1) {
|
||||
this.getDayDataList();
|
||||
} else if (this.listQuery.timeType === 3) {
|
||||
this.getLastDayDataList();
|
||||
} else {
|
||||
this.getDataList();
|
||||
}
|
||||
} else {
|
||||
this.getProductList();
|
||||
|
||||
}
|
||||
break;
|
||||
case 'export':
|
||||
@@ -834,6 +1013,9 @@ export default {
|
||||
case 'reset':
|
||||
this.$refs.searchBarForm.resetForm();
|
||||
this.$refs.searchBarForm.formInline.timeType = 1;
|
||||
this.formConfig[0].selectOptions = this.activeName === 'productLine'
|
||||
? this.timeTypeOptions.productLine
|
||||
: this.timeTypeOptions.product;
|
||||
this.listQuery = {
|
||||
pageSize: 100,
|
||||
pageNo: 1,
|
||||
@@ -842,12 +1024,9 @@ export default {
|
||||
};
|
||||
if (this.activeName === 'productLine') {
|
||||
this.getDayDataList();
|
||||
|
||||
} else {
|
||||
this.getProductList();
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
console.log(val);
|
||||
@@ -1097,6 +1276,28 @@ export default {
|
||||
return [...lineColumns, totalColumn];
|
||||
},
|
||||
// 为当天时调用的接口
|
||||
getLastDayDataList() {
|
||||
getPdlAutoReportNewSearchLastGroup().then((response) => {
|
||||
this.tableData = response.data.classData.map((item, index) => {
|
||||
item.originalLossNum = item.original?.lossNum;
|
||||
item.originalLossArea = item.original?.lossArea;
|
||||
item.edgeLossNum = item.edge?.lossNum;
|
||||
item.edgeLossArea = item.edge?.lossArea;
|
||||
item.drillLossNum = item.drill?.lossNum;
|
||||
item.drillLossArea = item.drill?.lossArea;
|
||||
item.coatingLossNum = item.coating?.lossNum;
|
||||
item.coatingLossArea = item.coating?.lossArea;
|
||||
item.silkLossNum = item.silk?.lossNum;
|
||||
item.silkLossArea = item.silk?.lossArea;
|
||||
item.temperingLossNum = item.tempering?.lossNum;
|
||||
item.temperingLossArea = item.tempering?.lossArea;
|
||||
item.packingLossNum = item.packing?.lossNum;
|
||||
item.packingLossArea = item.packing?.lossArea;
|
||||
return item;
|
||||
});
|
||||
// console.log(this.tableData, this.tableData2);
|
||||
});
|
||||
},
|
||||
getDayDataList() {
|
||||
getPdlAutoReportNewSearchNow().then((response) => {
|
||||
this.tableData = response.data.classData.map((item, index) => {
|
||||
@@ -1156,24 +1357,21 @@ export default {
|
||||
console.log(value);
|
||||
|
||||
this.listQuery.timeType = value;
|
||||
if (value === 1) {
|
||||
// 切换为“当天”:隐藏查询类型、报表类型、时间范围
|
||||
if (value === 2) {
|
||||
// 切换为“自定义”:显示查询类型和时间范围
|
||||
this.formConfig[1].type = 'select';
|
||||
this.$refs.searchBarForm.formInline.timeType = value;
|
||||
this.listQuery.timeType = value;
|
||||
this.formConfig[7].type = 'datePicker';
|
||||
} else {
|
||||
this.formConfig[1].type = '';
|
||||
this.formConfig[6].type = '';
|
||||
this.formConfig[7].type = '';
|
||||
this.$refs.searchBarForm.formInline.timeType = value;
|
||||
this.listQuery.timeType = value;
|
||||
|
||||
this.$refs.searchBarForm.formInline.searchType = undefined;
|
||||
this.$refs.searchBarForm.formInline.reportType = undefined;
|
||||
this.$refs.searchBarForm.formInline.timeVal = undefined;
|
||||
} else {
|
||||
// 切换为“自定义”:显示查询类型和时间范围
|
||||
this.formConfig[1].type = 'select';
|
||||
this.$refs.searchBarForm.formInline.timeType = value;
|
||||
this.listQuery.timeType = value;
|
||||
|
||||
this.formConfig[7].type = 'datePicker';
|
||||
}
|
||||
} else if (param === 'searchType') {
|
||||
if (value === 1) {
|
||||
@@ -1187,7 +1385,74 @@ export default {
|
||||
this.formConfig[7].type = 'datePicker';
|
||||
}
|
||||
} else if (param === 'reportType') {
|
||||
this.$refs.searchBarForm.formInline.timeVal = undefined;
|
||||
if (this.$refs.searchBarForm && this.$refs.searchBarForm.formInline) {
|
||||
const formInline = this.$refs.searchBarForm.formInline;
|
||||
// 精准判断:只有字段存在时,才置为undefined(不存在则不处理)
|
||||
if ('timeVal' in formInline) {
|
||||
formInline.timeVal = undefined;
|
||||
}
|
||||
if ('timeValWeek' in formInline) {
|
||||
formInline.timeValWeek = undefined;
|
||||
}
|
||||
if ('timeValMonth' in formInline) {
|
||||
formInline.timeValMonth = undefined;
|
||||
}
|
||||
if ('timeValYear' in formInline) {
|
||||
formInline.timeValYear = undefined;
|
||||
}
|
||||
}
|
||||
this.listQuery.startTime = undefined;
|
||||
this.listQuery.endTime = undefined;
|
||||
if (value === 1) {
|
||||
this.formConfig[7] = {
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'datetimerange',
|
||||
format: 'yyyy-MM-dd HH:mm:ss',
|
||||
valueFormat: 'timestamp',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
width: 350
|
||||
};
|
||||
} else if (value === 2) {
|
||||
this.formConfig[7] = {
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'week',
|
||||
placeholder: '选择日期',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'yyyy-MM-dd',
|
||||
param: 'timeValWeek',
|
||||
width: 250,
|
||||
};
|
||||
} else if (value === 3) {
|
||||
this.formConfig[7] = {
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'monthrange',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'timestamp',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeValMonth',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
width: 250,
|
||||
};
|
||||
} else if (value === 4) {
|
||||
this.formConfig[7] = {
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'year',
|
||||
placeholder: '选择年份',
|
||||
format: 'yyyy',
|
||||
valueFormat: 'timestamp',
|
||||
param: 'timeValYear',
|
||||
width: 250,
|
||||
};
|
||||
}
|
||||
} else if (param === 'factoryId') {
|
||||
// 切换工厂时刷新产线列表
|
||||
this.listQuery.lineId = [];
|
||||
@@ -1234,7 +1499,7 @@ export default {
|
||||
.content-wrapper {
|
||||
// flex: 1;
|
||||
width: 100%;
|
||||
height: calc(100vh - 303px);
|
||||
height: calc(100vh - 280px);
|
||||
// overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ const tableProps = [
|
||||
},
|
||||
{
|
||||
prop: 'palletNum',
|
||||
label: '下片托数'
|
||||
label: '一托玻璃数量/片'
|
||||
},
|
||||
{
|
||||
prop: 'startTime',
|
||||
@@ -92,7 +92,7 @@ const tableProps = [
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'outputNum',
|
||||
prop: 'length',
|
||||
label: '玻璃长度/mm'
|
||||
},
|
||||
{
|
||||
@@ -314,9 +314,10 @@ export default {
|
||||
case 'search':
|
||||
this.listQuery.pageNo = 1;
|
||||
this.listQuery.pageSize = 10;
|
||||
this.listQuery.productId = val.productId ? val.productId : undefined;
|
||||
this.listQuery.startTime = val.timeVal ? val.timeVal[0]: undefined;
|
||||
this.listQuery.endTime = val.timeVal ? val.timeVal[1]: undefined;
|
||||
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();
|
||||
|
||||
@@ -77,7 +77,7 @@ const tableProps = [
|
||||
},
|
||||
{
|
||||
prop: 'palletNum',
|
||||
label: '下片托数'
|
||||
label: '一托玻璃数量/片'
|
||||
},
|
||||
{
|
||||
prop: 'startTime',
|
||||
@@ -92,7 +92,7 @@ const tableProps = [
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
prop: 'outputNum',
|
||||
prop: 'length',
|
||||
label: '玻璃长度/mm'
|
||||
},
|
||||
{
|
||||
|
||||
@@ -262,6 +262,14 @@ export default {
|
||||
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),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<el-tabs v-model="activeLabel" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'全部数据'" name="table">
|
||||
<base-table-s ref="lineCurrentShiftTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'"
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData" :max-height="210" />
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData" :max-height="300" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000当天生产折线图\u3000'" name="graph">
|
||||
<div style="height: 230px;" v-if="activeLabel == 'graph'" class="graph">
|
||||
@@ -57,7 +57,7 @@
|
||||
<el-tabs v-model="activeLabelDay" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'全部数据'" name="table">
|
||||
<base-table-s ref="lineTodayTable" style="margin-bottom: 16px;" v-if="activeLabelDay == 'table'"
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData2" :max-height="210" />
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData2" :max-height="300" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000当天生产折线图\u3000'" name="graph">
|
||||
<div style="height: 230px;" v-if="activeLabelDay == 'graph'" class="graph">
|
||||
@@ -71,22 +71,68 @@
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-inner" v-if="listQuery.timeType === 3">
|
||||
<!-- 当班数据(占1/2剩余高度) -->
|
||||
<div class="content-card energyOverlimitLog">
|
||||
<span class="blue-block"></span>
|
||||
<span class="tip">上一班数据</span>
|
||||
<el-row style="margin-top: 10px;">
|
||||
<el-col class="custom-tabs">
|
||||
<el-tabs v-model="activeLabel" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'全部数据'" name="table">
|
||||
<base-table-s ref="lineCurrentShiftTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'"
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData" :max-height="300" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000当天生产折线图\u3000'" name="graph">
|
||||
<div style="height: 230px;" v-if="activeLabel == 'graph'" class="graph">
|
||||
<barChart v-if="tableData && tableData.length > 0" ref="barChart" height="230px"
|
||||
:bar-data="tableData" />
|
||||
<div v-else class="no-data-bg"></div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 当天数据(占1/2剩余高度) -->
|
||||
<div class="content-card energyOverlimitLog">
|
||||
<span class="blue-block"></span>
|
||||
<span class="tip">当天数据</span>
|
||||
<el-row style="margin-top: 10px;">
|
||||
<el-col class="custom-tabs">
|
||||
<el-tabs v-model="activeLabelDay" :stretch="true" @tab-click="handleTabClick">
|
||||
<el-tab-pane :label="'全部数据'" name="table">
|
||||
<base-table-s ref="lineTodayTable" style="margin-bottom: 16px;" v-if="activeLabelDay == 'table'"
|
||||
:page="1" :limit="100" :table-props="tableProps" :table-data="tableData2" :max-height="300" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'\u3000当天生产折线图\u3000'" name="graph">
|
||||
<div style="height: 230px;" v-if="activeLabelDay == 'graph'" class="graph">
|
||||
<barChart v-if="tableData2 && tableData2.length > 0" ref="barChart" height="230px"
|
||||
:bar-data="tableData2" />
|
||||
<div v-else class="no-data-bg"></div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 3.2 时间维度为“自定义”时的内容(两个平分高度的div) -->
|
||||
<div class="content-inner" v-else>
|
||||
<div class="content-inner" v-if="listQuery.timeType === 2">
|
||||
<div class="content-card energyOverlimitLog">
|
||||
<span class="blue-block"></span>
|
||||
<span class="tip" v-if="listQuery.startTime && listQuery.endTime">
|
||||
<span>{{ reportTypeMap[listQuery.reportType] }}</span>
|
||||
<span>
|
||||
{{ parseTime(listQuery.startTime) }} 至{{
|
||||
parseTime(listQuery.endTime) }}
|
||||
parseTime(listQuery.endTime) }}
|
||||
</span>
|
||||
</span>
|
||||
<span class="tip" v-else>生产表格数据 </span>
|
||||
<div class="graph">
|
||||
<base-table-s ref="lineCustomTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'" :page="1"
|
||||
:limit="100" :table-props="tableProps" :max-height="210" :table-data="tableDataCustom" />
|
||||
:limit="100" :table-props="tableProps" :max-height="300" :table-data="tableDataCustom" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -113,7 +159,7 @@
|
||||
<span class="tip">当班数据</span>
|
||||
<base-table-s ref="productCurrentShiftTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'"
|
||||
:page="1" :limit="100" :table-props="productTableProps" :table-data="productTableData"
|
||||
:max-height="210" />
|
||||
:max-height="300" />
|
||||
</div>
|
||||
|
||||
<!-- 当天数据(占1/2剩余高度) -->
|
||||
@@ -122,7 +168,7 @@
|
||||
<span class="tip">当天数据</span>
|
||||
<base-table-s ref="productTodayTable" style="margin-bottom: 16px;" v-if="activeLabelDay == 'table'"
|
||||
:page="1" :limit="100" :table-props="productTablePropsDay" :table-data="productTableDataDay"
|
||||
:max-height="210" />
|
||||
:max-height="300" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -142,7 +188,7 @@
|
||||
</span>
|
||||
<span class="tip" v-else>生产表格数据 </span>
|
||||
<base-table-s ref="productCustomTable" style="margin-bottom: 16px;" v-if="activeLabel == 'table'" :page="1"
|
||||
:limit="100" :table-props="productTableProps" :table-data="productTableData" :max-height="210" />
|
||||
:limit="100" :table-props="productTableProps" :table-data="productTableData" :max-height="300" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,7 +200,7 @@
|
||||
import { parseTime } from '@/filter/code-filter';
|
||||
import {
|
||||
getLineAuto, getPdList, getPdlAutoReportNewSearchNow, getProductAuto,
|
||||
getProcessAutoReportGroup, getProcessAutoReportDay, getProcessAutoReportNew
|
||||
getProcessAutoReportGroup, getProcessAutoReportDay, getProcessAutoReportNew, getPdlAutoReportNewSearchLastGroup
|
||||
} from '@/api/core/monitoring/auto';
|
||||
import { getFactoryPage } from '@/api/core/base/factory';
|
||||
import * as XLSX from 'xlsx';
|
||||
@@ -165,11 +211,11 @@ import ButtonNav from '@/components/ButtonNav';
|
||||
import { listData } from '@/api/system/dict/data';
|
||||
// 表格列配置
|
||||
const tableProps = [
|
||||
// {
|
||||
// prop: 'factoryName',
|
||||
// label: '工厂',
|
||||
// fixed: true
|
||||
// },
|
||||
{
|
||||
prop: 'factoryName',
|
||||
label: '工厂',
|
||||
fixed: true
|
||||
},
|
||||
{
|
||||
prop: 'lineName',
|
||||
label: '产线',
|
||||
@@ -368,15 +414,27 @@ export default {
|
||||
productTableDataDay: [],
|
||||
tableDataCustom: [],
|
||||
list: [], // 折线图数据
|
||||
timeTypeOptions: {
|
||||
productLine: [ // 按产线监控(包含上一班)
|
||||
{ id: 1, name: '当天' },
|
||||
{ id: 2, name: '自定义' },
|
||||
{ id: 3, name: '上一班' }
|
||||
],
|
||||
product: [ // 按产品监控(不含上一班)
|
||||
{ id: 1, name: '当天' },
|
||||
{ id: 2, name: '自定义' }
|
||||
]
|
||||
},
|
||||
formConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '时间维度',
|
||||
selectOptions: [
|
||||
{ id: 1, name: '当天' },
|
||||
{ id: 2, name: '自定义' }
|
||||
{ id: 2, name: '自定义' },
|
||||
{ id: 3, name: '上一班' }
|
||||
],
|
||||
width: 80,
|
||||
width: 100,
|
||||
onchange: true,
|
||||
// defaultSelect: 1,
|
||||
clearable: false,
|
||||
@@ -438,6 +496,7 @@ export default {
|
||||
{ id: 4, name: '年' }
|
||||
],
|
||||
width: 80,
|
||||
onchange: true,
|
||||
param: 'reportType'
|
||||
},
|
||||
{
|
||||
@@ -513,17 +572,20 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.buttonNav) {
|
||||
this.$refs.buttonNav.currentMenu = '按产品监控';
|
||||
this.formConfig[0].selectOptions = this.timeTypeOptions.product;
|
||||
}
|
||||
if (this.$refs.searchBarForm) {
|
||||
// this.$refs.searchBarForm.formInline.timeVal = [
|
||||
// yesterday.getTime(),
|
||||
// end.getTime()
|
||||
// ];
|
||||
|
||||
this.$refs.searchBarForm.formInline.timeType = 1
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
this.getProductList();
|
||||
this.getDayDataList();
|
||||
this.getPdLineList();
|
||||
const queryParams = {
|
||||
pageNo: 1,
|
||||
@@ -579,15 +641,21 @@ export default {
|
||||
|
||||
// 4. 根据类型设置差异化的表单配置(仅处理不同的部分)
|
||||
if (isProductLine) {
|
||||
// 按产线监控:显示产线,隐藏产品工艺和类型
|
||||
// 按产线监控:显示产线,隐藏产品工艺和类型,时间维度包含上一班
|
||||
this.formConfig[0].selectOptions = this.timeTypeOptions.productLine; // 恢复上一班选项
|
||||
this.formConfig[3].type = 'select'; // 显示产线
|
||||
this.formConfig[4].type = ''; // 隐藏产品工艺
|
||||
this.formConfig[5].type = ''; // 隐藏产品类型
|
||||
this.getDayDataList();
|
||||
|
||||
} else {
|
||||
// 按产品监控:显示产品工艺和类型,隐藏产线
|
||||
// 按产品监控:显示产品工艺和类型,隐藏产线,时间维度移除上一班
|
||||
this.formConfig[0].selectOptions = this.timeTypeOptions.product; // 不含上一班
|
||||
this.formConfig[3].type = ''; // 隐藏产线
|
||||
this.formConfig[4].type = 'select'; // 显示产品工艺
|
||||
this.formConfig[5].type = 'select'; // 显示产品类型
|
||||
this.getProductList();
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
@@ -596,48 +664,52 @@ export default {
|
||||
// 按产线监控
|
||||
if (this.activeName === 'productLine') {
|
||||
if (this.listQuery.timeType === 1) {
|
||||
// 产线-当天:导出当班 + 当天两个表格
|
||||
// 产线-当天:导出当班 + 当天两个表格(自定义汇总文件名)
|
||||
this.exportMultipleTables([
|
||||
{ ref: 'lineCurrentShiftTable', name: '产线监控_当班数据' },
|
||||
{ ref: 'lineTodayTable', name: '产线监控_当天数据' }
|
||||
]);
|
||||
], '产线监控_当班及当天数据汇总'); // 传入自定义汇总文件名
|
||||
} else if (this.listQuery.timeType === 1) {
|
||||
// 产线-当天:导出当班 + 当天两个表格(自定义汇总文件名)
|
||||
this.exportMultipleTables([
|
||||
{ ref: 'lineCurrentShiftTable', name: '产线监控_上一班数据' },
|
||||
{ ref: 'lineTodayTable', name: '产线监控_当天数据' }
|
||||
], '产线监控_当班及当天数据汇总'); // 传入自定义汇总文件名
|
||||
} else {
|
||||
// 产线-自定义:导出一个表格
|
||||
// 产线-自定义:导出一个表格(自定义文件名)
|
||||
this.exportSingleTable('lineCustomTable', '产线监控_自定义时间数据');
|
||||
}
|
||||
}
|
||||
// 按产品监控
|
||||
else {
|
||||
if (this.listQuery.timeType === 1) {
|
||||
// 产品-当天:导出当班 + 当天两个表格
|
||||
// 产品-当天:导出当班 + 当天两个表格(自定义汇总文件名)
|
||||
this.exportMultipleTables([
|
||||
{ ref: 'productCurrentShiftTable', name: '产品监控_当班数据' },
|
||||
{ ref: 'productTodayTable', name: '产品监控_当天数据' }
|
||||
]);
|
||||
], '产品监控_当班及当天数据汇总'); // 传入自定义汇总文件名
|
||||
} else {
|
||||
// 产品-自定义:导出一个表格
|
||||
// 产品-自定义:导出一个表格(自定义文件名)
|
||||
this.exportSingleTable('productCustomTable', '产品监控_自定义时间数据');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 导出单个表格
|
||||
// 导出单个表格(保持原有逻辑,文件名由调用方传入,已区分不同场景)
|
||||
exportSingleTable(refName, fileName) {
|
||||
const table = this.getTableDom(refName);
|
||||
if (!table) return;
|
||||
|
||||
// 克隆表格并移除固定列
|
||||
const clonedTable = table.cloneNode(true);
|
||||
this.removeFixedColumns(clonedTable);
|
||||
this.adjustTableForExport(clonedTable);
|
||||
|
||||
// 转换为工作簿并导出
|
||||
const workbook = XLSX.utils.table_to_book(clonedTable);
|
||||
const fullName = `${fileName}_${this.formatDate()}.xlsx`;
|
||||
XLSX.writeFile(workbook, fullName);
|
||||
},
|
||||
|
||||
// 导出多个表格(同一个Excel的不同sheet)
|
||||
exportMultipleTables(tables) {
|
||||
// 导出多个表格(新增自定义汇总文件名参数,适配不同选项卡)
|
||||
exportMultipleTables(tables, customSummaryName) {
|
||||
const workbook = XLSX.utils.book_new();
|
||||
let hasValidTable = false;
|
||||
|
||||
@@ -646,11 +718,9 @@ export default {
|
||||
if (!table) return;
|
||||
|
||||
hasValidTable = true;
|
||||
// 克隆表格并移除固定列
|
||||
const clonedTable = table.cloneNode(true);
|
||||
this.removeFixedColumns(clonedTable);
|
||||
this.adjustTableForExport(clonedTable);
|
||||
|
||||
// 转换为sheet并添加到工作簿
|
||||
const worksheet = XLSX.utils.table_to_sheet(clonedTable);
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, name);
|
||||
});
|
||||
@@ -660,31 +730,128 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
// 导出包含多个sheet的Excel
|
||||
const fullName = `生产监控数据汇总_${this.formatDate()}.xlsx`;
|
||||
// 动态生成汇总文件名:自定义名称 + 日期
|
||||
const fullName = `${customSummaryName}_${this.formatDate()}.xlsx`;
|
||||
XLSX.writeFile(workbook, fullName);
|
||||
},
|
||||
|
||||
// 辅助方法:获取表格DOM元素
|
||||
// 辅助方法:获取表格DOM元素(包含表头)
|
||||
getTableDom(refName) {
|
||||
const tableComponent = this.$refs[refName];
|
||||
if (!tableComponent) {
|
||||
this.$message.warning(`未找到${refName}表格`);
|
||||
return null;
|
||||
}
|
||||
// 获取表格组件内部的el-table DOM
|
||||
const tableDom = tableComponent.$el.querySelector('.el-table__body-wrapper table');
|
||||
if (!tableDom) {
|
||||
// 获取完整表格容器(包含表头和表体)
|
||||
const tableContainer = tableComponent.$el.querySelector('.el-table');
|
||||
if (!tableContainer) {
|
||||
this.$message.warning(`${refName}表格数据为空`);
|
||||
return null;
|
||||
}
|
||||
return tableDom;
|
||||
return tableContainer;
|
||||
},
|
||||
|
||||
// 辅助方法:移除固定列(避免重复导出)
|
||||
removeFixedColumns(table) {
|
||||
const fixedColumns = table.querySelectorAll('.el-table__fixed, .el-table__fixed-right');
|
||||
fixedColumns.forEach(col => col.remove());
|
||||
// 重点修复:调整表格结构(解决表头重复问题)
|
||||
adjustTableForExport(tableContainer) {
|
||||
// 1. 移除空表格提示和分页等无关元素
|
||||
const emptyCells = tableContainer.querySelectorAll('.el-table__empty-block, .el-pagination');
|
||||
emptyCells.forEach(cell => cell.remove());
|
||||
|
||||
// 2. 定位核心元素
|
||||
const mainTable = tableContainer.querySelector('.el-table__body-wrapper table'); // 主表体
|
||||
const fixedLeft = tableContainer.querySelector('.el-table__fixed'); // 左固定列容器
|
||||
const fixedRight = tableContainer.querySelector('.el-table__fixed-right'); // 右固定列容器
|
||||
|
||||
// 3. 提取所有表头行(支持多级表头,按层级收集)
|
||||
const allHeaderRows = []; // 存储所有层级的表头行(每行是一个单元格数组)
|
||||
|
||||
// 辅助函数:提取某个容器内的所有表头行(处理多级表头)
|
||||
const extractHeaderRows = (container) => {
|
||||
const headerWrapper = container?.querySelector('.el-table__header-wrapper table');
|
||||
if (!headerWrapper) return [];
|
||||
const thead = headerWrapper.querySelector('thead');
|
||||
if (!thead) return [];
|
||||
// 多级表头可能有多个tr(行)
|
||||
const headerRows = Array.from(thead.querySelectorAll('tr'));
|
||||
return headerRows.map(row => Array.from(row.querySelectorAll('th'))); // 每行的单元格数组
|
||||
};
|
||||
|
||||
// 收集左固定列的表头行(可能有多层)
|
||||
const fixedLeftHeaderRows = extractHeaderRows(fixedLeft);
|
||||
// 收集主表头的表头行(可能有多层)
|
||||
const mainHeaderRows = extractHeaderRows(tableContainer);
|
||||
// 收集右固定列的表头行(可能有多层)
|
||||
const fixedRightHeaderRows = extractHeaderRows(fixedRight);
|
||||
|
||||
// 4. 合并表头行(按层级对齐,左固定列 → 主表头 → 右固定列)
|
||||
// 确定最大表头层级(多级表头的行数)
|
||||
const maxLevel = Math.max(
|
||||
fixedLeftHeaderRows.length,
|
||||
mainHeaderRows.length,
|
||||
fixedRightHeaderRows.length
|
||||
);
|
||||
|
||||
// 按层级合并每行的单元格
|
||||
for (let i = 0; i < maxLevel; i++) {
|
||||
const rowCells = [];
|
||||
// 左固定列当前层级的单元格(不足则补空)
|
||||
rowCells.push(...(fixedLeftHeaderRows[i] || []));
|
||||
// 主表头当前层级的单元格(不足则补空)
|
||||
rowCells.push(...(mainHeaderRows[i] || []));
|
||||
// 右固定列当前层级的单元格(不足则补空)
|
||||
rowCells.push(...(fixedRightHeaderRows[i] || []));
|
||||
allHeaderRows.push(rowCells);
|
||||
}
|
||||
|
||||
// 5. 清理所有原有表头和固定列容器(避免干扰)
|
||||
tableContainer.querySelectorAll('thead').forEach(thead => thead.remove());
|
||||
tableContainer.querySelectorAll('.el-table__header-wrapper').forEach(wrapper => wrapper.remove());
|
||||
[fixedLeft, fixedRight].forEach(container => container?.remove());
|
||||
|
||||
// 6. 构建唯一表头并添加到主表体(支持多级表头)
|
||||
if (mainTable && allHeaderRows.length > 0) {
|
||||
const newThead = document.createElement('thead');
|
||||
// 按层级添加表头行
|
||||
allHeaderRows.forEach(cells => {
|
||||
const newTr = document.createElement('tr');
|
||||
cells.forEach(cell => {
|
||||
// 复制单元格(避免DOM残留引用问题)
|
||||
const clonedCell = cell.cloneNode(true);
|
||||
newTr.appendChild(clonedCell);
|
||||
});
|
||||
newThead.appendChild(newTr);
|
||||
});
|
||||
// 将新表头插入主表体最前面
|
||||
mainTable.insertBefore(newThead, mainTable.firstChild);
|
||||
}
|
||||
|
||||
// 7. 合并固定列数据到主表体(仅处理tbody数据)
|
||||
// 合并左固定列数据
|
||||
if (fixedLeft && mainTable) {
|
||||
const fixedLeftRows = fixedLeft.querySelectorAll('.el-table__body-wrapper tbody tr');
|
||||
const mainRows = mainTable.querySelectorAll('tbody tr');
|
||||
fixedLeftRows.forEach((fixedRow, index) => {
|
||||
if (mainRows[index]) {
|
||||
const fixedCells = Array.from(fixedRow.querySelectorAll('td'));
|
||||
fixedCells.forEach(cell => {
|
||||
mainRows[index].insertBefore(cell.cloneNode(true), mainRows[index].firstChild);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 合并右固定列数据
|
||||
if (fixedRight && mainTable) {
|
||||
const fixedRightRows = fixedRight.querySelectorAll('.el-table__body-wrapper tbody tr');
|
||||
const mainRows = mainTable.querySelectorAll('tbody tr');
|
||||
fixedRightRows.forEach((fixedRow, index) => {
|
||||
if (mainRows[index]) {
|
||||
const fixedCells = Array.from(fixedRow.querySelectorAll('td'));
|
||||
fixedCells.forEach(cell => {
|
||||
mainRows[index].appendChild(cell.cloneNode(true));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 辅助方法:格式化日期(用于文件名)
|
||||
@@ -698,7 +865,6 @@ export default {
|
||||
String(date.getMinutes()).padStart(2, '0')
|
||||
].join('');
|
||||
},
|
||||
|
||||
// 获取产线和工厂列表
|
||||
getPdLineList() {
|
||||
getPdList().then(res => {
|
||||
@@ -712,28 +878,85 @@ export default {
|
||||
|
||||
// 搜索/导出按钮点击
|
||||
buttonClick(val) {
|
||||
if (this.activeName === 'productLine') {
|
||||
this.listQuery.pageNo = 1;
|
||||
this.listQuery.pageSize = 10;
|
||||
this.listQuery.factoryId = val.factoryId || undefined;
|
||||
this.listQuery.process = val.process ? val.process : [];
|
||||
this.listQuery.lineId = val.lineId ? val.lineId : [];
|
||||
this.listQuery.processType = val.processType ? val.processType : [];
|
||||
this.listQuery.reportType = val.reportType || undefined;
|
||||
this.listQuery.timeType = val.timeType || undefined;
|
||||
this.listQuery.searchType = val.searchType || undefined;
|
||||
|
||||
// 处理不同时间选择类型
|
||||
if (val.timeVal) {
|
||||
this.listQuery.startTime = val.timeVal[0];
|
||||
this.listQuery.endTime = val.timeVal[1];
|
||||
} else if (val.timeValWeek) {
|
||||
// 周选择器
|
||||
const { startTime, endTime } = this.getWeekTimeRange(val.timeValWeek);
|
||||
this.listQuery.startTime = startTime;
|
||||
this.listQuery.endTime = endTime;
|
||||
} else if (val.timeValMonth) {
|
||||
// 月选择器
|
||||
this.listQuery.startTime = val.timeValMonth[0];
|
||||
this.listQuery.endTime = val.timeValMonth[1];
|
||||
} else if (val.timeValYear) {
|
||||
// 年选择器
|
||||
const { startTime, endTime } = this.getYearTimeRange(val.timeValYear);
|
||||
this.listQuery.startTime = startTime;
|
||||
this.listQuery.endTime = endTime;
|
||||
} else {
|
||||
this.listQuery.startTime = undefined;
|
||||
this.listQuery.endTime = undefined;
|
||||
}
|
||||
} else {
|
||||
this.listQuery.pageNo = 1;
|
||||
this.listQuery.pageSize = 10;
|
||||
this.listQuery.factoryId = val.factoryId || []
|
||||
this.listQuery.process = val.process ? val.process : [];
|
||||
this.listQuery.lineId = undefined;
|
||||
this.listQuery.processType = val.processType ? val.processType : [];
|
||||
this.listQuery.reportType = val.reportType || undefined;
|
||||
this.listQuery.timeType = val.timeType || undefined;
|
||||
this.listQuery.searchType = val.searchType || undefined;
|
||||
|
||||
// 处理不同时间选择类型
|
||||
if (val.timeVal) {
|
||||
this.listQuery.startTime = val.timeVal[0];
|
||||
this.listQuery.endTime = val.timeVal[1];
|
||||
} else if (val.timeValWeek) {
|
||||
// 周选择器
|
||||
const { startTime, endTime } = this.getWeekTimeRange(val.timeValWeek);
|
||||
this.listQuery.startTime = startTime;
|
||||
this.listQuery.endTime = endTime;
|
||||
} else if (val.timeValMonth) {
|
||||
// 月选择器
|
||||
this.listQuery.startTime = val.timeValMonth[0];
|
||||
this.listQuery.endTime = val.timeValMonth[1];
|
||||
} else if (val.timeValYear) {
|
||||
// 年选择器
|
||||
const { startTime, endTime } = this.getYearTimeRange(val.timeValYear);
|
||||
this.listQuery.startTime = startTime;
|
||||
this.listQuery.endTime = endTime;
|
||||
} else {
|
||||
this.listQuery.startTime = undefined;
|
||||
this.listQuery.endTime = undefined;
|
||||
}
|
||||
}
|
||||
switch (val.btnName) {
|
||||
case 'search':
|
||||
this.listQuery.pageNo = 1;
|
||||
this.listQuery.pageSize = 10;
|
||||
this.listQuery.factoryId = val.factoryId || undefined;
|
||||
this.listQuery.process = val.process ? val.process : [];
|
||||
this.listQuery.lineId = val.lineId ? val.lineId : [];
|
||||
this.listQuery.processType = val.processType ? val.processType : [];
|
||||
this.listQuery.reportType = val.reportType || undefined;
|
||||
this.listQuery.timeType = val.timeType || undefined;
|
||||
this.listQuery.searchType = val.searchType || undefined;
|
||||
this.listQuery.startTime = val.timeVal ? val.timeVal[0] : undefined;
|
||||
this.listQuery.endTime = val.timeVal ? val.timeVal[1] : undefined;
|
||||
if (this.activeName === 'productLine') {
|
||||
if (this.listQuery.timeType === 1) {
|
||||
this.getDayDataList();
|
||||
} else if (this.listQuery.timeType === 3) {
|
||||
this.getLastDayDataList();
|
||||
} else {
|
||||
this.getDataList();
|
||||
}
|
||||
} else {
|
||||
this.getProductList();
|
||||
|
||||
this.getProductList();
|
||||
}
|
||||
break;
|
||||
case 'export':
|
||||
@@ -742,6 +965,9 @@ export default {
|
||||
case 'reset':
|
||||
this.$refs.searchBarForm.resetForm();
|
||||
this.$refs.searchBarForm.formInline.timeType = 1;
|
||||
this.formConfig[0].selectOptions = this.activeName === 'productLine'
|
||||
? this.timeTypeOptions.productLine
|
||||
: this.timeTypeOptions.product;
|
||||
this.listQuery = {
|
||||
pageSize: 100,
|
||||
pageNo: 1,
|
||||
@@ -750,12 +976,9 @@ export default {
|
||||
};
|
||||
if (this.activeName === 'productLine') {
|
||||
this.getDayDataList();
|
||||
|
||||
} else {
|
||||
this.getProductList();
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
console.log(val);
|
||||
@@ -763,8 +986,8 @@ export default {
|
||||
},
|
||||
|
||||
getDataList() {
|
||||
if(!this.listQuery.startTime &&!this.listQuery.endTime ){
|
||||
return this.$modal.msgError('请选择时间');
|
||||
if (!this.listQuery.startTime && !this.listQuery.endTime) {
|
||||
return this.$modal.msgError('请选择时间');
|
||||
}
|
||||
this.dataListLoading = true;
|
||||
// const arr = ['日', '周', '月', '年'];
|
||||
@@ -798,7 +1021,7 @@ export default {
|
||||
console.log('resGroup');
|
||||
if (this.listQuery.timeType === 2) {
|
||||
const resGroup = await getProcessAutoReportNew(this.listQuery);
|
||||
console.log('resGroup',resGroup);
|
||||
console.log('resGroup', resGroup);
|
||||
|
||||
// 格式化数据:lineDetList提取到外层,键名加lineId前缀
|
||||
const formatData = (rawList) => {
|
||||
@@ -827,7 +1050,7 @@ export default {
|
||||
|
||||
// 处理当班和当天数据(分别存储)
|
||||
this.productTableData = formatData(resGroup.data.list); // 当班数据
|
||||
console.log(this.productTableData,'productTableData');
|
||||
console.log(this.productTableData, 'productTableData');
|
||||
|
||||
// --------------------------
|
||||
// 生成当班数据的动态表头
|
||||
@@ -1005,6 +1228,28 @@ export default {
|
||||
return [...lineColumns, totalColumn];
|
||||
},
|
||||
// 为当天时调用的接口
|
||||
getLastDayDataList() {
|
||||
getPdlAutoReportNewSearchLastGroup().then((response) => {
|
||||
this.tableData = response.data.classData.map((item, index) => {
|
||||
item.originalLossNum = item.original?.lossNum;
|
||||
item.originalLossArea = item.original?.lossArea;
|
||||
item.edgeLossNum = item.edge?.lossNum;
|
||||
item.edgeLossArea = item.edge?.lossArea;
|
||||
item.drillLossNum = item.drill?.lossNum;
|
||||
item.drillLossArea = item.drill?.lossArea;
|
||||
item.coatingLossNum = item.coating?.lossNum;
|
||||
item.coatingLossArea = item.coating?.lossArea;
|
||||
item.silkLossNum = item.silk?.lossNum;
|
||||
item.silkLossArea = item.silk?.lossArea;
|
||||
item.temperingLossNum = item.tempering?.lossNum;
|
||||
item.temperingLossArea = item.tempering?.lossArea;
|
||||
item.packingLossNum = item.packing?.lossNum;
|
||||
item.packingLossArea = item.packing?.lossArea;
|
||||
return item;
|
||||
});
|
||||
// console.log(this.tableData, this.tableData2);
|
||||
});
|
||||
},
|
||||
getDayDataList() {
|
||||
getPdlAutoReportNewSearchNow().then((response) => {
|
||||
this.tableData = response.data.classData.map((item, index) => {
|
||||
@@ -1060,28 +1305,26 @@ export default {
|
||||
|
||||
// 搜索栏下拉选择变化
|
||||
handleSearchBarChanged({ param, value }) {
|
||||
console.log(value, param);
|
||||
if (param === 'timeType') {
|
||||
console.log(value);
|
||||
|
||||
this.listQuery.timeType = value;
|
||||
if (value === 1) {
|
||||
// 切换为“当天”:隐藏查询类型、报表类型、时间范围
|
||||
if (value === 2) {
|
||||
// 切换为“自定义”:显示查询类型和时间范围
|
||||
this.formConfig[1].type = 'select';
|
||||
this.$refs.searchBarForm.formInline.timeType = value;
|
||||
this.listQuery.timeType = value;
|
||||
this.formConfig[7].type = 'datePicker';
|
||||
} else {
|
||||
this.formConfig[1].type = '';
|
||||
this.formConfig[6].type = '';
|
||||
this.formConfig[7].type = '';
|
||||
this.$refs.searchBarForm.formInline.timeType = value;
|
||||
this.listQuery.timeType = value;
|
||||
|
||||
this.$refs.searchBarForm.formInline.searchType = undefined;
|
||||
this.$refs.searchBarForm.formInline.reportType = undefined;
|
||||
this.$refs.searchBarForm.formInline.timeVal = undefined;
|
||||
} else {
|
||||
// 切换为“自定义”:显示查询类型和时间范围
|
||||
this.formConfig[1].type = 'select';
|
||||
this.$refs.searchBarForm.formInline.timeType = value;
|
||||
this.listQuery.timeType = value;
|
||||
|
||||
this.formConfig[7].type = 'datePicker';
|
||||
}
|
||||
} else if (param === 'searchType') {
|
||||
if (value === 1) {
|
||||
@@ -1095,7 +1338,74 @@ export default {
|
||||
this.formConfig[7].type = 'datePicker';
|
||||
}
|
||||
} else if (param === 'reportType') {
|
||||
this.$refs.searchBarForm.formInline.timeVal = undefined;
|
||||
if (this.$refs.searchBarForm && this.$refs.searchBarForm.formInline) {
|
||||
const formInline = this.$refs.searchBarForm.formInline;
|
||||
// 精准判断:只有字段存在时,才置为undefined(不存在则不处理)
|
||||
if ('timeVal' in formInline) {
|
||||
formInline.timeVal = undefined;
|
||||
}
|
||||
if ('timeValWeek' in formInline) {
|
||||
formInline.timeValWeek = undefined;
|
||||
}
|
||||
if ('timeValMonth' in formInline) {
|
||||
formInline.timeValMonth = undefined;
|
||||
}
|
||||
if ('timeValYear' in formInline) {
|
||||
formInline.timeValYear = undefined;
|
||||
}
|
||||
}
|
||||
this.listQuery.startTime = undefined;
|
||||
this.listQuery.endTime = undefined;
|
||||
if (value === 1) {
|
||||
this.formConfig[7] = {
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'datetimerange',
|
||||
format: 'yyyy-MM-dd HH:mm:ss',
|
||||
valueFormat: 'timestamp',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeVal',
|
||||
width: 350
|
||||
};
|
||||
} else if (value === 2) {
|
||||
this.formConfig[7] = {
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'week',
|
||||
placeholder: '选择日期',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'yyyy-MM-dd',
|
||||
param: 'timeValWeek',
|
||||
width: 250,
|
||||
};
|
||||
} else if (value === 3) {
|
||||
this.formConfig[7] = {
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'monthrange',
|
||||
format: 'yyyy-MM-dd',
|
||||
valueFormat: 'timestamp',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
param: 'timeValMonth',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
width: 250,
|
||||
};
|
||||
} else if (value === 4) {
|
||||
this.formConfig[7] = {
|
||||
type: 'datePicker',
|
||||
label: '时间范围',
|
||||
dateType: 'year',
|
||||
placeholder: '选择年份',
|
||||
format: 'yyyy',
|
||||
valueFormat: 'timestamp',
|
||||
param: 'timeValYear',
|
||||
width: 250,
|
||||
};
|
||||
}
|
||||
} else if (param === 'factoryId') {
|
||||
// 切换工厂时刷新产线列表
|
||||
this.listQuery.lineId = [];
|
||||
@@ -1142,7 +1452,7 @@ export default {
|
||||
.content-wrapper {
|
||||
// flex: 1;
|
||||
width: 100%;
|
||||
height: calc(100vh - 303px);
|
||||
height: calc(100vh - 280px);
|
||||
// overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
<!--
|
||||
* @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" />
|
||||
<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"
|
||||
@@ -17,34 +11,47 @@
|
||||
<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> -->
|
||||
<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 * as XLSX from 'xlsx'
|
||||
import FileSaver from 'file-saver'
|
||||
import jsPDF from 'jspdf'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { getCostOriginRadioHisData, getPdList } from '@/api/core/monitoring/index';
|
||||
import { exportCostOriginRadioHisData } from '../../../../api/core/monitoring';
|
||||
|
||||
const tableProps = [
|
||||
// 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: '报表类型'
|
||||
@@ -52,12 +59,11 @@ const tableProps = [
|
||||
{
|
||||
prop: 'time',
|
||||
label: '日期',
|
||||
// filter: parseTime,
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
{
|
||||
prop: 'bindObjectName',
|
||||
label: '产线'
|
||||
label: '产线'
|
||||
},
|
||||
{
|
||||
prop: 'thick',
|
||||
@@ -67,11 +73,11 @@ const tableProps = [
|
||||
prop: 'speed',
|
||||
label: '在线速度'
|
||||
},
|
||||
{
|
||||
{
|
||||
prop: 'width',
|
||||
label: '掰边宽度'
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
prop: 'inArea',
|
||||
label: '拉引量/㎡'
|
||||
},
|
||||
@@ -79,21 +85,83 @@ const tableProps = [
|
||||
prop: 'outArea',
|
||||
label: '下片面积/㎡'
|
||||
},
|
||||
{
|
||||
{
|
||||
prop: 'ratio',
|
||||
label: '良品率'
|
||||
},
|
||||
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
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
urlOptions: {
|
||||
getDataListURL: getCostOriginRadioHisData
|
||||
},
|
||||
tableData: [],
|
||||
listQuery: {
|
||||
pageSize: 10,
|
||||
@@ -101,181 +169,366 @@ export default {
|
||||
total: 1,
|
||||
bindObjectId: undefined,
|
||||
statisticType: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined
|
||||
},
|
||||
pdLineList:[],
|
||||
pdLineList: [],
|
||||
exportLoading: false,
|
||||
dataListLoading: false,
|
||||
selectedList: [],
|
||||
dialogVisible: false,
|
||||
selectedList: [],
|
||||
dialogVisible: false,
|
||||
addOrEditTitle: '',
|
||||
addOrUpdateVisible: false,
|
||||
tableProps,
|
||||
tableProps,
|
||||
tableBtn: [
|
||||
{
|
||||
type: 'edit',
|
||||
btnName: '编辑',
|
||||
},
|
||||
].filter((v) => v),
|
||||
tableData: [],
|
||||
fileName: '',
|
||||
].filter(v => v),
|
||||
fileName: '',
|
||||
formConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '维度',
|
||||
label: '报表类型',
|
||||
onchange: true,
|
||||
selectOptions: [
|
||||
{
|
||||
id: '0',
|
||||
name:'班组'
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
name: '日'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '周'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: '月'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: '年'
|
||||
}
|
||||
{ id: '0', name: '班组' },
|
||||
{ id: '1', name: '日' },
|
||||
{ id: '2', name: '周' },
|
||||
{ id: '3', name: '月' },
|
||||
{ id: '4', name: '年' }
|
||||
],
|
||||
param: 'statisticType'
|
||||
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-MM-dd',
|
||||
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: [],
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
param: 'bindObjectId'
|
||||
},
|
||||
|
||||
{
|
||||
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: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
{
|
||||
type: 'separate',
|
||||
},
|
||||
{
|
||||
// type: this.$auth.hasPermi('base:factory:export') ? 'button' : '',
|
||||
type: 'button',
|
||||
btnName: '导出',
|
||||
name: 'export',
|
||||
color: 'warning',
|
||||
}
|
||||
],
|
||||
};
|
||||
},
|
||||
{
|
||||
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() {
|
||||
this.$refs.searchBarForm.formInline.statisticType = '1';
|
||||
// Vue2 中 $refs 需在 $nextTick 中访问(确保 DOM 渲染完成)
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.searchBarForm) {
|
||||
this.$refs.searchBarForm.formInline.statisticType = '1';
|
||||
}
|
||||
});
|
||||
this.listQuery.statisticType = '1';
|
||||
this.getDataList()
|
||||
this.getPdLineList()
|
||||
},
|
||||
this.getDataList();
|
||||
this.getPdLineList();
|
||||
},
|
||||
methods: {
|
||||
selectType(val) {
|
||||
// 报表类型切换时的回调(如需扩展可在此添加逻辑)
|
||||
console.log('报表类型切换:', val);
|
||||
},
|
||||
handleClick(val) {
|
||||
console.log(val);
|
||||
console.log('操作按钮点击:', val);
|
||||
if (val.type === 'edit') {
|
||||
this.addOrUpdateVisible= true
|
||||
this.addOrUpdateVisible = true;
|
||||
// Vue2 中 $nextTick 确保子组件已渲染
|
||||
this.$nextTick(() => {
|
||||
this.$refs.addOrUpdate.init(val.data);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getPdLineList() {
|
||||
getPdList().then((res) => {
|
||||
this.formConfig[1].selectOptions = res.data || []
|
||||
this.pdLineList = res.data || []; // 保存产线数据
|
||||
})
|
||||
},
|
||||
selectChange(val) {
|
||||
console.log(val)
|
||||
this.selectedList = val
|
||||
},
|
||||
buttonClick(val) {
|
||||
console.log('val', 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.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 => {
|
||||
const arr = ['班组','日', '周', '月', '年'];
|
||||
this.tableData = response.data?.list?.map((item) => {
|
||||
item.reportType = arr[this.listQuery.statisticType];
|
||||
item.statisticType = this.listQuery.statisticType
|
||||
|
||||
// 匹配 bindObjectName
|
||||
const targetLine = this.pdLineList.find(line => line.id === item.bindObjectId);
|
||||
item.bindObjectName = targetLine ? targetLine.name : ''; // 赋值名称,无匹配则为空
|
||||
return item;
|
||||
});
|
||||
this.listQuery.total = response.data.total;
|
||||
this.dataListLoading = false;
|
||||
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() {
|
||||
// 处理查询参数
|
||||
let params = { ...this.listQuery };
|
||||
params.pageNo = undefined;
|
||||
params.pageSize = undefined;
|
||||
this.$modal.confirm('是否确认导出原片报表?').then(() => {
|
||||
this.exportLoading = true;
|
||||
return exportCostOriginRadioHisData(params);
|
||||
}).then(response => {
|
||||
this.$download.excel(response, '原片报表.xls');
|
||||
this.exportLoading = false;
|
||||
}).catch(() => { });
|
||||
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 || undefined;
|
||||
this.dataForm.equipmentName = data.equipmentName || undefined;
|
||||
this.dataForm.lineId = data.lineId || undefined;
|
||||
|
||||
|
||||
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>
|
||||
498
src/views/equipment/equipmentOverview/alarm-or-updata.vue
Normal file
498
src/views/equipment/equipmentOverview/alarm-or-updata.vue
Normal file
@@ -0,0 +1,498 @@
|
||||
<template>
|
||||
<el-dialog :visible.sync="visible" width="40%" @close="destroyAllCharts" 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">
|
||||
<div v-show="activeLabel === 'duration'" id="barChart" style="width: 100%; height: 400px;"></div>
|
||||
<!-- 报警次数-饼图 -->
|
||||
<div v-show="activeLabel === 'times'" id="pieChart" style="width: 100%; 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';
|
||||
// import { ElEmpty } from 'element-plus';
|
||||
|
||||
// 图表颜色配置(统一风格)
|
||||
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: true, // 是否有数据标识
|
||||
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', // 默认激活时长tab
|
||||
dataForm: {
|
||||
equipmentId: undefined,
|
||||
equipmentName: undefined,
|
||||
lineId: undefined
|
||||
},
|
||||
// 存储图表实例,用于销毁
|
||||
chartInstances: {
|
||||
bar: null,
|
||||
pie: null
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 初始化默认日期(当天)
|
||||
this.initDefaultDate();
|
||||
},
|
||||
methods: {
|
||||
// 初始化默认日期(当天零点到23:59:59)
|
||||
initDefaultDate() {
|
||||
const today = new Date();
|
||||
const start = new Date(today.setHours(0, 0, 0, 0)).getTime();
|
||||
const end = new Date(today.setHours(23, 59, 59, 999)).getTime();
|
||||
this.formConfig[0].defaultSelect = [start, end];
|
||||
this.listQuery.startTime = start;
|
||||
this.listQuery.endTime = end;
|
||||
},
|
||||
|
||||
// 切换Tab时加载对应图表
|
||||
handleTabClick() {
|
||||
this.getDataList();
|
||||
},
|
||||
|
||||
// 搜索按钮点击事件
|
||||
buttonClick(val) {
|
||||
switch (val.btnName) {
|
||||
case 'search':
|
||||
this.listQuery.startTime = val.timeVal?.[0];
|
||||
this.listQuery.endTime = val.timeVal?.[1];
|
||||
this.getDataList();
|
||||
break;
|
||||
case 'link':
|
||||
this.disabled = true;
|
||||
this.connectSSEBatch(this.listQuery.equipmentIds);
|
||||
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.hasData = originData.length > 0;
|
||||
|
||||
if (this.hasData) {
|
||||
// 根据当前Tab渲染对应图表
|
||||
this.activeLabel === 'duration'
|
||||
? this.renderBarChart(originData)
|
||||
: this.renderPieChart(originData);
|
||||
} else {
|
||||
// 无数据时销毁已有图表
|
||||
this.destroyAllCharts();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取报警数据失败:', error);
|
||||
this.hasData = false;
|
||||
this.destroyAllCharts();
|
||||
}
|
||||
},
|
||||
|
||||
// 渲染报警时长-柱状图
|
||||
renderBarChart(originData) {
|
||||
// 先销毁原有图表
|
||||
this.destroyChart('chart');
|
||||
|
||||
// 按报警时长降序排序
|
||||
const sortedData = [...originData].sort((a, b) => b.alarmDuration - a.alarmDuration);
|
||||
|
||||
// 处理图表数据
|
||||
const xData = sortedData.map(item => this.truncateText(item.alarmContent, 8)); // 文本截断(最多8字)
|
||||
const seriesData = sortedData.map(item => item.alarmDuration);
|
||||
|
||||
const chartDom = document.getElementById('barChart');
|
||||
this.chartInstances.bar = echarts.init(chartDom);
|
||||
|
||||
const option = {
|
||||
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>报警时长:${item.alarmDuration}</div>
|
||||
<div>占比:${item.alarmDurationRatio.toFixed(2)}%</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '5%',
|
||||
right: '5%',
|
||||
bottom: '18%', // 底部留足空间显示x轴标签
|
||||
top: '10%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xData,
|
||||
axisTick: { alignWithLabel: true },
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
// rotate: 35, // 标签旋转
|
||||
fontSize: 12,
|
||||
color: CHART_CONFIG.lightFontColor
|
||||
},
|
||||
axisLine: { lineStyle: { color: '#e8e8e8' } }
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
fontSize: 11,
|
||||
color: CHART_CONFIG.lightFontColor,
|
||||
// formatter: '{value}s' // 显示单位
|
||||
},
|
||||
axisLine: { lineStyle: { color: '#e8e8e8' } },
|
||||
splitLine: { lineStyle: { color: '#f5f5f5' } },
|
||||
// 扩展y轴最大值,避免label超出
|
||||
max: (value) => value.max * 1.2
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '报警时长',
|
||||
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);
|
||||
// 监听窗口 resize
|
||||
this.addResizeListener('bar');
|
||||
},
|
||||
|
||||
// 渲染报警次数-饼图
|
||||
renderPieChart(originData) {
|
||||
// 先销毁原有图表
|
||||
this.destroyChart('pie');
|
||||
|
||||
// 按报警次数降序排序
|
||||
const sortedData = [...originData].sort((a, b) => b.alarmCount - a.alarmCount);
|
||||
|
||||
// 处理图表数据(合并占比过小的项为"其他")
|
||||
const pieData = this.handlePieData(sortedData);
|
||||
|
||||
const chartDom = document.getElementById('pieChart');
|
||||
this.chartInstances.pie = echarts.init(chartDom);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
padding: 10,
|
||||
textStyle: { fontSize: 11 },
|
||||
formatter: (params) => {
|
||||
return `
|
||||
<div style="text-align: left;">
|
||||
<div>${params.name}</div>
|
||||
<div>报警次数:${params.value} 次</div>
|
||||
<div>占比:${params.percent.toFixed(2)}%</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '报警次数',
|
||||
type: 'pie',
|
||||
radius: ['50%', '70%'], // 环形饼图
|
||||
center: ['50%', '50%'], // 饼图居中显示
|
||||
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); // 最多8字
|
||||
return `${truncatedName}(${params.value}次, ${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,
|
||||
// 高亮样式(hover时)
|
||||
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);
|
||||
// 监听窗口 resize
|
||||
this.addResizeListener('pie');
|
||||
},
|
||||
// 处理饼图数据(合并占比<5%的项)
|
||||
handlePieData(data) {
|
||||
const threshold = 5; // 阈值:5%
|
||||
let otherCount = 0;
|
||||
const mainData = data.filter(item => {
|
||||
if (item.alarmCountRatio >= threshold) {
|
||||
return true;
|
||||
} else {
|
||||
otherCount += item.alarmCount;
|
||||
return false;
|
||||
}
|
||||
}).map(item => ({
|
||||
name: item.alarmContent,
|
||||
value: item.alarmCount,
|
||||
ratio: item.alarmCountRatio
|
||||
}));
|
||||
|
||||
// 如果有"其他"项,添加到数据中
|
||||
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;
|
||||
},
|
||||
|
||||
// 添加窗口resize监听
|
||||
addResizeListener(type) {
|
||||
const chart = this.chartInstances[type];
|
||||
if (chart) {
|
||||
const resizeHandler = () => chart.resize();
|
||||
window.addEventListener('resize', resizeHandler);
|
||||
// 存储resize处理器,用于后续移除
|
||||
chart.resizeHandler = resizeHandler;
|
||||
}
|
||||
},
|
||||
|
||||
// 销毁单个图表
|
||||
destroyChart(type) {
|
||||
const chart = this.chartInstances[type];
|
||||
if (chart) {
|
||||
// 移除resize监听
|
||||
window.removeEventListener('resize', chart.resizeHandler);
|
||||
chart.dispose();
|
||||
this.chartInstances[type] = null;
|
||||
}
|
||||
},
|
||||
|
||||
// 销毁所有图表
|
||||
destroyAllCharts() {
|
||||
Object.keys(this.chartInstances).forEach(type => {
|
||||
this.destroyChart(type);
|
||||
});
|
||||
},
|
||||
|
||||
// 初始化弹窗数据
|
||||
init(data) {
|
||||
this.dataForm = {
|
||||
equipmentId: data.equipmentId || undefined,
|
||||
equipmentName: data.equipmentName || '未知设备',
|
||||
lineId: data.lineId || '未知产线'
|
||||
};
|
||||
this.listQuery.equipmentId = data.equipmentId || undefined;
|
||||
this.visible = true;
|
||||
this.$nextTick(() => {
|
||||
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;
|
||||
/* 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>
|
||||
1252
src/views/equipment/equipmentOverview/index.vue
Normal file
1252
src/views/equipment/equipmentOverview/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -51,6 +51,7 @@
|
||||
src="/static/videos/login.webm"
|
||||
muted
|
||||
autoplay
|
||||
id="video"
|
||||
loop
|
||||
style="
|
||||
user-select: none;
|
||||
@@ -338,7 +339,8 @@ export default {
|
||||
SysUserSocialTypeEnum: SystemUserSocialTypeEnum,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
created() {
|
||||
|
||||
// 租户开关
|
||||
this.tenantEnable = getTenantEnable();
|
||||
if (this.tenantEnable) {
|
||||
@@ -356,8 +358,15 @@ export default {
|
||||
this.redirect = this.$route.query.redirect
|
||||
? decodeURIComponent(this.$route.query.redirect)
|
||||
: undefined;
|
||||
this.getCookie();
|
||||
},
|
||||
this.getCookie();
|
||||
|
||||
|
||||
},
|
||||
mounted () {
|
||||
const video = document.getElementById('video');
|
||||
// 设置为0.5倍速,数值越小速度越慢(0.5为半速,0.75为0.75倍速等)
|
||||
video.playbackRate = 0.2;
|
||||
},
|
||||
methods: {
|
||||
getCode() {
|
||||
// 情况一,未开启:则直接登录
|
||||
|
||||
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>
|
||||
674
src/views/quality/qualityIsra/defectVisualization.vue
Normal file
674
src/views/quality/qualityIsra/defectVisualization.vue
Normal file
@@ -0,0 +1,674 @@
|
||||
<template>
|
||||
<div class="status-timegraph-container" style="background: #f2f4f9; flex: 1; display: flex; flex-direction: column">
|
||||
<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 class="blue-title">
|
||||
图表时间维度
|
||||
<div style="position: relative; display: flex; align-items: center; gap: 10px; margin-top: 10px;">
|
||||
<el-button type="primary" @click="handleExport"
|
||||
style="position: absolute;top: 0px;right: 10px;z-index: 9999;">
|
||||
导出
|
||||
</el-button>
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick" style="flex: 1;">
|
||||
|
||||
<!-- 班组标签页 -->
|
||||
<el-tab-pane label="班组" name="group">
|
||||
<!-- 修改:使用四宫格布局容器 -->
|
||||
<div class="chart-grid">
|
||||
<div id="mapGroupMain" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="mapGroupMainScrap" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="listGroupMain" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="listGroupMainScrap" class="chart-container" style="height: 400px;"></div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 日标签页 -->
|
||||
<el-tab-pane label="日" name="day">
|
||||
<!-- 修改:使用四宫格布局容器 -->
|
||||
<div class="chart-grid">
|
||||
<div id="mapDayMain" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="mapDayMainScrap" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="listDayMain" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="listDayMainScrap" class="chart-container" style="height: 400px;"></div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 周标签页 -->
|
||||
<el-tab-pane label="周" name="week">
|
||||
<!-- 修改:使用四宫格布局容器 -->
|
||||
<div class="chart-grid">
|
||||
<div id="mapWeekMain" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="mapWeekMainScrap" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="listWeekMain" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="listWeekMainScrap" class="chart-container" style="height: 400px;"></div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 月标签页 -->
|
||||
<el-tab-pane label="月" name="month">
|
||||
<!-- 修改:使用四宫格布局容器 -->
|
||||
<div class="chart-grid">
|
||||
<div id="mapMonthMain" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="mapMonthMainScrap" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="listMonthMain" class="chart-container" style="height: 400px;"></div>
|
||||
<div id="listMonthMainScrap" class="chart-container" style="height: 400px;"></div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getQualityIsraPage,
|
||||
} from '@/api/monitoring/qualityIsra';
|
||||
import moment from 'moment';
|
||||
import * as echarts from 'echarts';
|
||||
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
|
||||
import { parseTime } from '@/utils/ruoyi';
|
||||
import { getPdList } from '@/api/core/monitoring/auto';
|
||||
import html2canvas from 'html2canvas';
|
||||
export default {
|
||||
name: 'QualityIsra',
|
||||
mixins: [tableHeightMixin],
|
||||
data() {
|
||||
return {
|
||||
isFold: false,
|
||||
list: [],
|
||||
dynamicProps: [],
|
||||
activeName: 'group', // 默认激活“日”标签页
|
||||
// 新增:班组图表接口URL(与后端确认一致)
|
||||
groupMapUrl: '/extend/check-isra-statistics/groupMap',
|
||||
groupListUrl: '/extend/check-isra-statistics/groupList',
|
||||
// 原有接口URL:保持不变
|
||||
dayMapUrl: '/extend/check-isra-statistics/dayMap',
|
||||
weekMapUrl: '/extend/check-isra-statistics/weekMap',
|
||||
monthMapUrl: '/extend/check-isra-statistics/monthMap',
|
||||
dayListUrl: '/extend/check-isra-statistics/dayList',
|
||||
weekListUrl: '/extend/check-isra-statistics/weekList',
|
||||
monthListUrl: '/extend/check-isra-statistics/monthList',
|
||||
searchBarFormConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '是否报废',
|
||||
placeholder: '请选择是否报废',
|
||||
param: 'checkDiscard',
|
||||
selectOptions: [
|
||||
{ name: '否', id: 0 },
|
||||
{ name: '是', id: 1 }
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '缺陷类型',
|
||||
placeholder: '请选择缺陷类型',
|
||||
param: 'checkType',
|
||||
selectOptions: [],
|
||||
labelField: 'name',
|
||||
valueField: 'name',
|
||||
defaultSelect: [],
|
||||
filterable: true
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
labelField: 'name',
|
||||
valueField: 'name',
|
||||
param: 'lineName',
|
||||
filterable: true,
|
||||
defaultSelect: []
|
||||
},
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '时间段',
|
||||
dateType: 'datetimerange',
|
||||
format: 'yyyy-MM-dd HH:mm:ss',
|
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始日期',
|
||||
endPlaceholder: '结束日期',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
param: 'checkTime',
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
checkDiscard: undefined,
|
||||
// checkType: undefined,
|
||||
// lineName: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// 初始化折叠状态(如需使用可取消注释)
|
||||
// this.isFold = this.searchBarWidth('QualityIsraBox', 1198);
|
||||
},
|
||||
computed: {
|
||||
tableProps() {
|
||||
return [
|
||||
{
|
||||
prop: 'checkType',
|
||||
label: '缺陷类型',
|
||||
},
|
||||
{
|
||||
prop: 'sumNum',
|
||||
label: '缺陷总数',
|
||||
},
|
||||
...this.dynamicProps,
|
||||
];
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 从路由参数获取产线信息并回显
|
||||
if (this.$route.query.lineName) {
|
||||
this.queryParams.lineName = this.$route.query.lineName;
|
||||
this.searchBarFormConfig[2].defaultSelect = this.$route.query.lineName;
|
||||
}
|
||||
// 从路由参数获取时间信息并回显
|
||||
if (this.$route.query.originalGlassOutputTime) {
|
||||
const time = new Date(Number(this.$route.query.originalGlassOutputTime));
|
||||
this.queryParams.startTime = parseTime(time);
|
||||
this.queryParams.endTime = parseTime(time);
|
||||
this.searchBarFormConfig[3].defaultSelect = [
|
||||
this.queryParams.startTime,
|
||||
this.queryParams.endTime,
|
||||
];
|
||||
}
|
||||
// 初始化数据
|
||||
this.getData();
|
||||
this.getDict();
|
||||
},
|
||||
methods: {
|
||||
/** 标签页切换事件 */
|
||||
handleClick() {
|
||||
this.getData();
|
||||
},
|
||||
|
||||
/** 核心:获取并渲染图表数据(支持班组/日/周/月) */
|
||||
getData() {
|
||||
// 1. 根据当前激活的标签页,选择对应的接口URL和图表容器ID
|
||||
let mapUrl, listUrl, mapDomId, listDomId, mapDomIdScrap, listDomIdScrap;
|
||||
switch (this.activeName) {
|
||||
case 'group':
|
||||
mapUrl = this.groupMapUrl;
|
||||
listUrl = this.groupListUrl;
|
||||
mapDomId = 'mapGroupMain';
|
||||
listDomId = 'listGroupMain';
|
||||
mapDomIdScrap = 'mapGroupMainScrap';
|
||||
listDomIdScrap = 'listGroupMainScrap';
|
||||
break;
|
||||
case 'day':
|
||||
mapUrl = this.dayMapUrl;
|
||||
listUrl = this.dayListUrl;
|
||||
mapDomId = 'mapDayMain';
|
||||
listDomId = 'listDayMain';
|
||||
mapDomIdScrap = 'mapGroupDayScrap';
|
||||
listDomIdScrap = 'listGroupDayScrap';
|
||||
break;
|
||||
case 'week':
|
||||
mapUrl = this.weekMapUrl;
|
||||
listUrl = this.weekListUrl;
|
||||
mapDomId = 'mapWeekMain';
|
||||
listDomId = 'listWeekMain';
|
||||
mapDomIdScrap = 'mapGroupWeekScrap';
|
||||
listDomIdScrap = 'listGroupWeekScrap';
|
||||
break;
|
||||
case 'month':
|
||||
mapUrl = this.monthMapUrl;
|
||||
listUrl = this.monthListUrl;
|
||||
mapDomId = 'mapMonthMain';
|
||||
listDomId = 'listMonthMain';
|
||||
mapDomIdScrap = 'mapGroupMonthScrap';
|
||||
listDomIdScrap = 'listGroupMonthScrap';
|
||||
break;
|
||||
}
|
||||
|
||||
// 2. 请求“各类型缺陷对比图”数据
|
||||
this.$axios({
|
||||
url: mapUrl,
|
||||
method: 'get',
|
||||
params: this.queryParams
|
||||
}).then((res) => {
|
||||
const mapArr = [];
|
||||
const mapLegendData = [];
|
||||
// 处理接口返回数据(确保与后端数据格式匹配)
|
||||
for (const type in res.data) {
|
||||
const dataArr = [];
|
||||
const xAxisData = [];
|
||||
res.data[type].forEach(ele => {
|
||||
dataArr.push(ele.num); // 缺陷数量
|
||||
// 班组标签页使用“班组名称”作为X轴,其他标签页使用“时间”
|
||||
xAxisData.push(ele.checkTime);
|
||||
});
|
||||
mapArr.push({
|
||||
name: type, // 缺陷类型名称
|
||||
type: 'line', // 折线图
|
||||
data: dataArr,
|
||||
xAxisData: xAxisData // 存储当前系列的X轴数据
|
||||
});
|
||||
mapLegendData.push(type);
|
||||
}
|
||||
|
||||
// 渲染“各类型缺陷对比图”
|
||||
const mapChartDom = document.getElementById(mapDomId);
|
||||
if (mapChartDom) {
|
||||
const myChart = echarts.init(mapChartDom);
|
||||
myChart.clear(); // 清除原有图表
|
||||
myChart.setOption({
|
||||
title: { text: '所有缺陷对比图' },
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: { data: mapLegendData, top: '10%', y: 'top', x: 'left' },
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', top: '20%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: mapArr.length > 0 ? mapArr[0].xAxisData : [] // 使用第一个系列的X轴数据
|
||||
},
|
||||
yAxis: { type: 'value', name: '缺陷数量' },
|
||||
series: mapArr
|
||||
});
|
||||
// 监听窗口 resize,自动调整图表大小
|
||||
window.addEventListener('resize', () => myChart.resize());
|
||||
}
|
||||
});
|
||||
|
||||
this.$axios({
|
||||
url: mapUrl,
|
||||
method: 'get',
|
||||
params: {
|
||||
startTime: this.queryParams.startTime,
|
||||
endTime: this.queryParams.endTime,
|
||||
checkDiscard:true
|
||||
}
|
||||
}).then((res) => {
|
||||
const mapArr = [];
|
||||
const mapLegendData = [];
|
||||
// 处理接口返回数据(确保与后端数据格式匹配)
|
||||
for (const type in res.data) {
|
||||
const dataArr = [];
|
||||
const xAxisData = [];
|
||||
res.data[type].forEach(ele => {
|
||||
dataArr.push(ele.num); // 缺陷数量
|
||||
// 班组标签页使用“班组名称”作为X轴,其他标签页使用“时间”
|
||||
xAxisData.push(ele.checkTime);
|
||||
});
|
||||
mapArr.push({
|
||||
name: type, // 缺陷类型名称
|
||||
type: 'line', // 折线图
|
||||
data: dataArr,
|
||||
xAxisData: xAxisData // 存储当前系列的X轴数据
|
||||
});
|
||||
mapLegendData.push(type);
|
||||
}
|
||||
|
||||
// 渲染“各类型缺陷对比图”
|
||||
const mapChartDom = document.getElementById(mapDomIdScrap);
|
||||
if (mapChartDom) {
|
||||
const myChart = echarts.init(mapChartDom);
|
||||
myChart.clear(); // 清除原有图表
|
||||
myChart.setOption({
|
||||
title: { text: '所有缺陷对比图' },
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: { data: mapLegendData, top: '10%', y: 'top', x: 'left' },
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', top: '20%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: mapArr.length > 0 ? mapArr[0].xAxisData : [] // 使用第一个系列的X轴数据
|
||||
},
|
||||
yAxis: { type: 'value', name: '缺陷数量' },
|
||||
series: mapArr
|
||||
});
|
||||
// 监听窗口 resize,自动调整图表大小
|
||||
window.addEventListener('resize', () => myChart.resize());
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 请求“缺陷率趋势图”数据
|
||||
this.$axios({
|
||||
url: listUrl,
|
||||
method: 'get',
|
||||
params: this.queryParams
|
||||
}).then((res) => {
|
||||
const listNumArr = []; // 缺陷数量
|
||||
const listRatioArr = []; // 缺陷率
|
||||
const listXAxisData = []; // X轴数据
|
||||
|
||||
// 处理接口返回数据(确保与后端数据格式匹配)
|
||||
res.data.forEach(ele => {
|
||||
listNumArr.push(ele.num);
|
||||
listRatioArr.push(ele.ratio); // 缺陷率(百分比)
|
||||
// 班组标签页使用“班组名称”作为X轴,其他标签页使用“时间”
|
||||
listXAxisData.push(this.activeName === 'group' ? ele.groupName : ele.checkTime);
|
||||
});
|
||||
|
||||
// 渲染“缺陷率趋势图”
|
||||
const listChartDom = document.getElementById(listDomId);
|
||||
if (listChartDom) {
|
||||
const myChart = echarts.init(listChartDom);
|
||||
myChart.clear(); // 清除原有图表
|
||||
myChart.setOption({
|
||||
title: { text: '所有缺陷率趋势图' },
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: { data: ['缺陷数量', '缺陷率'], top: '10%' },
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', top: '20%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: listXAxisData
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '缺陷数量',
|
||||
axisLabel: { formatter: '{value}' }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '缺陷率',
|
||||
axisLabel: { formatter: '{value} %' },
|
||||
position: 'right' // 缺陷率Y轴放在右侧
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '缺陷数量',
|
||||
type: 'bar',
|
||||
barWidth: '3%',
|
||||
data: listNumArr,
|
||||
itemStyle: { color: 'rgba(40, 138, 255, 1)' } // 柱状图颜色
|
||||
},
|
||||
{
|
||||
name: '缺陷率',
|
||||
type: 'line',
|
||||
yAxisIndex: 1, // 关联右侧Y轴
|
||||
data: listRatioArr,
|
||||
itemStyle: { color: 'rgba(115, 222, 147, 1)' }, // 折线图颜色
|
||||
symbol: 'circle', // 标记点样式
|
||||
symbolSize: 6
|
||||
}
|
||||
]
|
||||
});
|
||||
// 监听窗口 resize,自动调整图表大小
|
||||
window.addEventListener('resize', () => myChart.resize());
|
||||
}
|
||||
});
|
||||
|
||||
this.$axios({
|
||||
url: listUrl,
|
||||
method: 'get',
|
||||
params: {
|
||||
startTime: this.queryParams.startTime,
|
||||
endTime: this.queryParams.endTime,
|
||||
checkDiscard: true
|
||||
}
|
||||
}).then((res) => {
|
||||
const listNumArr = []; // 缺陷数量
|
||||
const listRatioArr = []; // 缺陷率
|
||||
const listXAxisData = []; // X轴数据
|
||||
|
||||
// 处理接口返回数据(确保与后端数据格式匹配)
|
||||
res.data.forEach(ele => {
|
||||
listNumArr.push(ele.num);
|
||||
listRatioArr.push(ele.ratio); // 缺陷率(百分比)
|
||||
// 班组标签页使用“班组名称”作为X轴,其他标签页使用“时间”
|
||||
listXAxisData.push(this.activeName === 'group' ? ele.groupName : ele.checkTime);
|
||||
});
|
||||
|
||||
// 渲染“缺陷率趋势图”
|
||||
const listChartDom = document.getElementById(listDomIdScrap);
|
||||
if (listChartDom) {
|
||||
const myChart = echarts.init(listChartDom);
|
||||
myChart.clear(); // 清除原有图表
|
||||
myChart.setOption({
|
||||
title: { text: '所有缺陷率趋势图' },
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: { data: ['缺陷数量', '缺陷率'], top: '10%' },
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', top: '20%', containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: listXAxisData
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '缺陷数量',
|
||||
axisLabel: { formatter: '{value}' }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '缺陷率',
|
||||
axisLabel: { formatter: '{value} %' },
|
||||
position: 'right' // 缺陷率Y轴放在右侧
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '缺陷数量',
|
||||
type: 'bar',
|
||||
barWidth: '3%',
|
||||
data: listNumArr,
|
||||
itemStyle: { color: 'rgba(40, 138, 255, 1)' } // 柱状图颜色
|
||||
},
|
||||
{
|
||||
name: '缺陷率',
|
||||
type: 'line',
|
||||
yAxisIndex: 1, // 关联右侧Y轴
|
||||
data: listRatioArr,
|
||||
itemStyle: { color: 'rgba(115, 222, 147, 1)' }, // 折线图颜色
|
||||
symbol: 'circle', // 标记点样式
|
||||
symbolSize: 6
|
||||
}
|
||||
]
|
||||
});
|
||||
// 监听窗口 resize,自动调整图表大小
|
||||
window.addEventListener('resize', () => myChart.resize());
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** 新增:导出数据功能 */
|
||||
handleExport() {
|
||||
// 1. 找到当前激活标签页内的 .chart-wrapper 容器
|
||||
const container = document.querySelector(`.el-tab-pane[aria-selected="true"] .chart-wrapper`);
|
||||
|
||||
if (!container) {
|
||||
this.$message.warning('未找到图表容器');
|
||||
console.error('导出失败:未找到 .chart-wrapper 容器');
|
||||
return;
|
||||
}
|
||||
|
||||
this.$message.info('正在生成图片,请稍候...');
|
||||
|
||||
// 2. 获取当前标签页的两个图表实例,并强制刷新它们
|
||||
// 这是解决问题的关键步骤
|
||||
const chartIds = this.getChartIdsByActiveName();
|
||||
chartIds.forEach(id => {
|
||||
const chartDom = document.getElementById(id);
|
||||
if (chartDom) {
|
||||
const chartInstance = echarts.getInstanceByDom(chartDom);
|
||||
if (chartInstance) {
|
||||
chartInstance.resize(); // 强制图表重新渲染
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 使用 setTimeout 等待图表渲染完成后再进行截图
|
||||
// 延迟时间可以根据你的图表复杂度调整,一般 100-300ms 足够
|
||||
setTimeout(() => {
|
||||
html2canvas(container, {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
logging: false,
|
||||
backgroundColor: null,
|
||||
// 增加一个配置,确保能捕获到所有元素
|
||||
windowWidth: container.scrollWidth,
|
||||
windowHeight: container.scrollHeight
|
||||
}).then(canvas => {
|
||||
const imgBase64 = canvas.toDataURL('image/png');
|
||||
const link = document.createElement('a');
|
||||
link.href = imgBase64;
|
||||
|
||||
const titleMap = { group: '班组', day: '日', week: '周', month: '月' };
|
||||
const title = titleMap[this.activeName] || '数据';
|
||||
link.download = `${title}度缺陷分析报告.png`;
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
this.$message.success('图表导出成功!');
|
||||
}).catch(error => {
|
||||
this.$message.error('图表导出失败!');
|
||||
console.error('html2canvas 截图失败:', error);
|
||||
});
|
||||
}, 200); // 等待 200 毫秒
|
||||
},
|
||||
|
||||
// 新增一个辅助方法,根据当前激活的标签页获取对应的图表 ID
|
||||
getChartIdsByActiveName() {
|
||||
switch (this.activeName) {
|
||||
case 'group':
|
||||
return ['mapGroupMain', 'listGroupMain'];
|
||||
case 'day':
|
||||
return ['mapDayMain', 'listDayMain'];
|
||||
case 'week':
|
||||
return ['mapWeekMain', 'listWeekMain'];
|
||||
case 'month':
|
||||
return ['mapMonthMain', 'listMonthMain'];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
/** 获取搜索栏的字典数据(缺陷类型、产线列表) */
|
||||
async getDict() {
|
||||
// 获取缺陷类型列表
|
||||
const defectRes = await this.$axios({
|
||||
url: '/extend/check-isra-standards/page',
|
||||
method: 'get',
|
||||
params: { pageSize: 100, pageNo: 1 }
|
||||
});
|
||||
this.searchBarFormConfig[1].selectOptions = defectRes.data.list || [];
|
||||
|
||||
// 获取产线列表
|
||||
const lineRes = await getPdList();
|
||||
this.searchBarFormConfig[2].selectOptions = lineRes.data || [];
|
||||
},
|
||||
|
||||
/** 查询列表数据(如需使用表格可取消注释) */
|
||||
// getList() {
|
||||
// this.getDataList();
|
||||
// },
|
||||
|
||||
/** 表格数据查询(如需使用表格可取消注释) */
|
||||
// async getDataList() {
|
||||
// this.loading = true;
|
||||
// try {
|
||||
// const { data } = await getQualityIsraPage(this.queryParams);
|
||||
// this.dynamicProps = this.filterNameData(data.nameData);
|
||||
// this.list = this.filterData(data.data);
|
||||
// } catch (error) {
|
||||
// console.error('获取表格数据失败:', error);
|
||||
// } finally {
|
||||
// this.loading = false;
|
||||
// }
|
||||
// },
|
||||
|
||||
/** 过滤动态表格列名(如需使用表格可取消注释) */
|
||||
// filterNameData(nameData) {
|
||||
// const nameSet = new Set(nameData.map(nd => nd.name));
|
||||
// return Array.from(nameSet).sort().map(name => ({ prop: name, label: name }));
|
||||
// },
|
||||
|
||||
/** 过滤表格数据(如需使用表格可取消注释) */
|
||||
// filterData(data) {
|
||||
// return data.map(item => {
|
||||
// const keyValuePairs = {};
|
||||
// item.data.forEach(d => {
|
||||
// keyValuePairs[d.dynamicName] = d.dynamicValue;
|
||||
// });
|
||||
// return { ...keyValuePairs, sumNum: item.sumNum, checkType: item.checkType };
|
||||
// });
|
||||
// },
|
||||
|
||||
/** 搜索按钮点击事件(如需使用搜索栏可取消注释) */
|
||||
// handleSearchBarBtnClick(val) {
|
||||
// if (val.btnName === 'search') {
|
||||
// this.queryParams.checkDiscard = (val?.checkDiscard === 0 || val?.checkDiscard === 1) ? val?.checkDiscard : undefined;
|
||||
// this.queryParams.lineName = val.lineName ? val.lineName : undefined;
|
||||
// this.queryParams.checkType = val.checkType ? val.checkType : undefined;
|
||||
// this.queryParams.startTime = val.checkTime ? val.checkTime[0] : undefined;
|
||||
// this.queryParams.endTime = val.checkTime ? val.checkTime[1] : undefined;
|
||||
|
||||
// this.getList();
|
||||
// this.getData();
|
||||
// }
|
||||
// }
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.blue-title {
|
||||
position: relative;
|
||||
padding: 4px 0;
|
||||
padding-left: 12px;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
font-weight: 700;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 6px;
|
||||
height: 16px;
|
||||
width: 4px;
|
||||
border-radius: 1px;
|
||||
background: #0b58ff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 新增:四宫格布局样式 */
|
||||
.chart-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
/* 创建两列,宽度相等 */
|
||||
grid-template-rows: repeat(2, auto);
|
||||
/* 创建两行,高度自适应内容 */
|
||||
gap: 20px;
|
||||
/* 图表之间的间距 */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
270
src/views/quality/qualityIsra/dialogForm.vue
Normal file
270
src/views/quality/qualityIsra/dialogForm.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<!--
|
||||
filename: dialogForm.vue
|
||||
author: liubin
|
||||
date: 2023-09-11 15:55:13
|
||||
description: DialogForm for qualityInspectionRecord only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="innerDataForm"
|
||||
label-width="100px"
|
||||
v-loading="formLoading">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
label="检测内容"
|
||||
prop="inspectionDetId"
|
||||
:rules="[{ required: true, message: '检测内容不能为空', trigger: 'blur' }]">
|
||||
<el-select
|
||||
v-model="innerDataForm.inspectionDetId"
|
||||
placeholder="请选择检测内容"
|
||||
filterable
|
||||
clearable
|
||||
@change="handleInspectionDetChange">
|
||||
<el-option
|
||||
v-for="opt in inspectionDetList"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
label="来源"
|
||||
prop="source"
|
||||
:rules="[{ required: true, message: '来源不能为空', trigger: 'blur' }]">
|
||||
<el-select
|
||||
v-model="innerDataForm.source"
|
||||
placeholder="请选择来源"
|
||||
filterable
|
||||
clearable
|
||||
@change="$emit('update', innerDataForm)">
|
||||
<el-option
|
||||
v-for="opt in [
|
||||
{ label: '手动', value: 1 },
|
||||
{ label: '自动', value: 2 },
|
||||
]"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
label="产线"
|
||||
prop="productionLineId"
|
||||
:rules="[{ required: true, message: '产线不能为空', trigger: 'blur' }]">
|
||||
<el-select
|
||||
v-model="innerDataForm.productionLineId"
|
||||
placeholder="请选择产线"
|
||||
filterable
|
||||
clearable
|
||||
@change="handleProductlineChange">
|
||||
<el-option
|
||||
v-for="opt in productionLineList"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
label="工段"
|
||||
prop="sectionId"
|
||||
:rules="[{ required: true, message: '工段不能为空', trigger: 'blur' }]">
|
||||
<el-select
|
||||
v-model="innerDataForm.sectionId"
|
||||
placeholder="请选择工段"
|
||||
clearable
|
||||
filterable
|
||||
@change="$emit('update', innerDataForm)">
|
||||
<el-option
|
||||
v-for="opt in sectionList"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="检测人员" prop="checkPerson">
|
||||
<el-input
|
||||
v-model="innerDataForm.checkPerson"
|
||||
clearable
|
||||
@change="$emit('update', innerDataForm)"
|
||||
placeholder="请输入检测人员" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
label="检测时间"
|
||||
prop="checkTime"
|
||||
:rules="[{ required: true, message: '检测时间不能为空', trigger: 'blur' }]">
|
||||
<el-date-picker
|
||||
v-model="innerDataForm.checkTime"
|
||||
type="datetime"
|
||||
placeholder="请选择检测时间"
|
||||
value-format="timestamp"
|
||||
@change="$emit('update', innerDataForm)"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col>
|
||||
<el-form-item label="描述" prop="explainText">
|
||||
<el-input
|
||||
v-model="innerDataForm.explainText"
|
||||
placeholder="请输入描述信息"
|
||||
@change="$emit('update', innerDataForm)"
|
||||
type="textarea"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="innerDataForm.remark"
|
||||
@change="$emit('update', innerDataForm)"
|
||||
placeholder="请输入备注"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DialogForm',
|
||||
model: {
|
||||
prop: 'dataForm',
|
||||
event: 'update',
|
||||
},
|
||||
emits: ['update'],
|
||||
components: {},
|
||||
props: {
|
||||
dataForm: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formLoading: true,
|
||||
inspectionDetList: [],
|
||||
productionLineList: [],
|
||||
sectionList: [],
|
||||
innerDataForm: {},
|
||||
cacheInspectionDetList: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
Promise.all([this.getProductLineList(), this.getInspectionDetList()]).then(
|
||||
() => {
|
||||
this.formLoading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
watch: {
|
||||
// 'innerDataForm.productionLineId': {
|
||||
// handler: async function (plId) {
|
||||
// if (plId) await this.getWorksectionList(plId);
|
||||
// },
|
||||
// immediate: true,
|
||||
// },
|
||||
dataForm: {
|
||||
handler: function (dataForm) {
|
||||
this.innerDataForm = Object.assign({}, dataForm);
|
||||
|
||||
if (dataForm.productionLineId)
|
||||
this.getWorksectionList(dataForm.productionLineId);
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/** 模拟透传 ref */
|
||||
validate(cb) {
|
||||
return this.$refs.form.validate(cb);
|
||||
},
|
||||
resetFields(args) {
|
||||
return this.$refs.form.resetFields(args);
|
||||
},
|
||||
|
||||
handleInspectionDetChange(value) {
|
||||
const { id, content } = this.cacheInspectionDetList.find(
|
||||
(item) => item.id == value
|
||||
);
|
||||
this.innerDataForm.inspectionDetId = id;
|
||||
this.innerDataForm.inspectionDetContent = content;
|
||||
this.$emit('update', this.innerDataForm);
|
||||
},
|
||||
|
||||
async handleProductlineChange(id) {
|
||||
// await this.getWorksectionList(id);
|
||||
this.innerDataForm.sectionId = null;
|
||||
this.$emit('update', this.innerDataForm);
|
||||
},
|
||||
|
||||
// getCode
|
||||
async getCode(url) {
|
||||
const response = await this.$axios(url);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// 获取产线列表
|
||||
async getProductLineList() {
|
||||
const response = await this.$axios('/base/core-production-line/listAll');
|
||||
this.productionLineList = response.data.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
},
|
||||
|
||||
// 获取检测内容列表
|
||||
async getInspectionDetList() {
|
||||
const response = await this.$axios(
|
||||
'/base/quality-inspection-det/listAll'
|
||||
);
|
||||
this.cacheInspectionDetList = response.data;
|
||||
this.inspectionDetList = response.data.map((item) => ({
|
||||
label: item.content,
|
||||
value: item.id,
|
||||
}));
|
||||
},
|
||||
|
||||
// 获取工段列表
|
||||
async getWorksectionList(plId) {
|
||||
const response = await this.$axios(
|
||||
'/base/workshop-section/listByParentId',
|
||||
{
|
||||
params: {
|
||||
id: plId,
|
||||
},
|
||||
}
|
||||
);
|
||||
this.sectionList = response.data.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-date-editor,
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
468
src/views/quality/qualityIsra/index.vue
Normal file
468
src/views/quality/qualityIsra/index.vue
Normal file
@@ -0,0 +1,468 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- <div class="blue-title">生产节拍时序图</div> -->
|
||||
<SearchBar :formConfigs="searchBarFormConfig" ref="search-bar" @headBtnClick="handleSearchBarBtnClick" />
|
||||
|
||||
<!-- 列表 -->
|
||||
<base-table :max-height="tableH" :table-props="tableProps" :page="1" :limit="20" :table-data="list">
|
||||
</base-table>
|
||||
<!-- </el-row> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getQualityIsraPage,
|
||||
// getQualityIsraDayMap,
|
||||
// getQualityIsraWeekMap,
|
||||
// getQualityIsraMonthMap,
|
||||
// getQualityIsraDayList,
|
||||
// getQualityIsraWeekList,
|
||||
// getQualityIsraMonthList,
|
||||
} from '@/api/monitoring/qualityIsra';
|
||||
// import Editor from '@/components/Editor';
|
||||
import moment from 'moment';
|
||||
// import DialogForm from './dialogForm.vue';
|
||||
import * as echarts from 'echarts';
|
||||
import tableHeightMixin from '@/mixins/lb/tableHeightMixin';
|
||||
// import { getPdList } from '@/api/base/coreProductionLine';
|
||||
import { parseTime } from '@/utils/ruoyi';
|
||||
import { getPdList, } from '@/api/core/monitoring/auto';
|
||||
// import basicPageMixin from '@/mixins/lb/basicPageMixin';
|
||||
export default {
|
||||
name: 'QualityIsra',
|
||||
// components: {
|
||||
// DialogForm,
|
||||
// },
|
||||
mixins: [tableHeightMixin],
|
||||
data() {
|
||||
return {
|
||||
isFold: false,
|
||||
list: [],
|
||||
dynamicProps: [],
|
||||
activeName: 'day',
|
||||
dayMapUrl: '/extend/check-isra-statistics/dayMap',
|
||||
weekMapUrl: '/extend/check-isra-statistics/weekMap',
|
||||
monthMapUrl: '/extend/check-isra-statistics/monthMap',
|
||||
dayListUrl: '/extend/check-isra-statistics/dayList',
|
||||
weekListUrl: '/extend/check-isra-statistics/weekList',
|
||||
monthListUrl: '/extend/check-isra-statistics/monthList',
|
||||
searchBarFormConfig: [
|
||||
{
|
||||
type: 'select',
|
||||
label: '是否报废',
|
||||
placeholder: '请选择是否报废',
|
||||
param: 'checkDiscard',
|
||||
selectOptions: [
|
||||
{ name: '否', id: 0 },
|
||||
{ name: '是', id: 1 }
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '缺陷类型',
|
||||
placeholder: '请选择缺陷类型',
|
||||
param: 'checkType',
|
||||
selectOptions: [],
|
||||
labelField: 'name',
|
||||
valueField: 'name',
|
||||
defaultSelect: [],
|
||||
filterable: true
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
label: '产线',
|
||||
selectOptions: [],
|
||||
labelField: 'name',
|
||||
valueField: 'name',
|
||||
param: 'lineName',
|
||||
filterable: true,
|
||||
defaultSelect: []
|
||||
},
|
||||
{
|
||||
type: 'datePicker',
|
||||
label: '时间段',
|
||||
dateType: 'datetimerange', // datetimerange
|
||||
// format: 'yyyy-MM-dd HH:mm:ss',
|
||||
format: 'yyyy-MM-dd HH:mm:ss',
|
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
||||
rangeSeparator: '-',
|
||||
startPlaceholder: '开始日期',
|
||||
endPlaceholder: '结束日期',
|
||||
defaultTime: ['00:00:00', '23:59:59'],
|
||||
param: 'checkTime',
|
||||
// width: 350,
|
||||
},
|
||||
{
|
||||
type:'button',
|
||||
btnName: '查询',
|
||||
name: 'search',
|
||||
color: 'primary',
|
||||
},
|
||||
],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
checkDiscard: undefined,
|
||||
checkType:undefined,
|
||||
lineName: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
// productionLineId: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// this.getProductLineList();
|
||||
// this.isFold = this.searchBarWidth('QualityIsraBox', 1198);
|
||||
},
|
||||
computed: {
|
||||
tableProps() {
|
||||
return [
|
||||
{
|
||||
// width: 128,
|
||||
prop: 'checkType',
|
||||
label: '缺陷类型',
|
||||
},
|
||||
{
|
||||
// width: 128,
|
||||
prop: 'sumNum',
|
||||
label: '缺陷总数',
|
||||
},
|
||||
...this.dynamicProps,
|
||||
];
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.$route.query.lineName) {
|
||||
// console.log('打印看看产线', this.$route.query.lineName)
|
||||
this.queryParams.lineName = this.$route.query.lineName
|
||||
this.searchBarFormConfig[2].defaultSelect = this.$route.query.lineName
|
||||
}
|
||||
if (this.$route.query.originalGlassOutputTime) {
|
||||
console.log('你好', this.$route.query.originalGlassOutputTime)
|
||||
this.queryParams.startTime = parseTime(new Date(Number(this.$route.query.originalGlassOutputTime)))
|
||||
this.queryParams.endTime = parseTime(new Date(Number(this.$route.query.originalGlassOutputTime)))
|
||||
this.searchBarFormConfig[3].defaultSelect = [
|
||||
this.queryParams.startTime,
|
||||
this.queryParams.endTime,
|
||||
];
|
||||
}
|
||||
this.getList()
|
||||
this.getData()
|
||||
this.getDict()
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.getData()
|
||||
},
|
||||
getData() {
|
||||
this.$axios({
|
||||
url: this.activeName === 'day' ? this.dayMapUrl : this.activeName === 'week' ? this.weekMapUrl : this.monthMapUrl,
|
||||
method: 'get',
|
||||
params: this.queryParams
|
||||
}).then((res) => {
|
||||
let mapArr= []
|
||||
let mapLegendData = []
|
||||
let obj = {
|
||||
name: '',
|
||||
type: 'line',
|
||||
// stack: 'Total',
|
||||
data: [],
|
||||
mapXAxisData: [],
|
||||
}
|
||||
// let mapXAxisData = []
|
||||
for (let i in res.data) {
|
||||
|
||||
// console.log(i)
|
||||
let dataArr = []
|
||||
res.data[i].forEach(ele => {
|
||||
dataArr.push(ele.num)
|
||||
obj.mapXAxisData.push(ele.checkTime)
|
||||
})
|
||||
obj.name = i
|
||||
obj.data = dataArr
|
||||
mapLegendData.push(i)
|
||||
mapArr.push(obj)
|
||||
}
|
||||
console.log(mapArr);
|
||||
// console.log(res.data[res]);
|
||||
var chartDom = this.activeName === 'day' ? document.getElementById('mapDayMain') : this.activeName === 'week' ? document.getElementById('mapWeekMain') : document.getElementById('mapMonthMain')
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option;
|
||||
option = {
|
||||
title: {
|
||||
text: '各类型缺陷对比图',
|
||||
// top:'5px'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: mapLegendData,
|
||||
top: "10%",
|
||||
y: 'top',
|
||||
x:'left'
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
top:'20%',
|
||||
containLabel: true
|
||||
},
|
||||
// toolbox: {
|
||||
// feature: {
|
||||
// saveAsImage: {}
|
||||
// }
|
||||
// },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
// boundaryGap: false,
|
||||
data: mapArr[0].mapXAxisData
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: mapArr
|
||||
}
|
||||
myChart.clear()
|
||||
option && myChart.setOption(option);
|
||||
})
|
||||
this.$axios({
|
||||
url: this.activeName === 'day' ? this.dayListUrl : this.activeName === 'week' ? this.weekListUrl : this.monthListUrl,
|
||||
method: 'get',
|
||||
params: this.queryParams
|
||||
}).then((res) => {
|
||||
// console.log(res);
|
||||
let listNumArr = []
|
||||
let listRatioArr = []
|
||||
// let listLegendData = []
|
||||
let listXAxisData = []
|
||||
// for (let i in res.data) {
|
||||
// console.log(i)
|
||||
// let dataArr = []
|
||||
res.data.forEach(ele => {;
|
||||
listNumArr.push(ele.num)
|
||||
listRatioArr.push(ele.ratio)
|
||||
listXAxisData.push(ele.checkTime)
|
||||
})
|
||||
console.log(listNumArr);
|
||||
// obj.name = i
|
||||
// obj.data = dataArr
|
||||
// listLegendData.push(i)
|
||||
// listArr.push(obj)
|
||||
// }
|
||||
// console.log(res.data[res]);
|
||||
var chartDom = this.activeName === 'day' ? document.getElementById('listDayMain') : this.activeName === 'week' ? document.getElementById('listWeekMain') : document.getElementById('listMonthMain')
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option;
|
||||
option = {
|
||||
title: {
|
||||
text: '缺陷率趋势图'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ['缺陷数量', '缺陷率'],
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
// toolbox: {
|
||||
// feature: {
|
||||
// saveAsImage: {}
|
||||
// }
|
||||
// },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
// boundaryGap: false,
|
||||
data: listXAxisData
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '缺陷数量',
|
||||
// min: 0,
|
||||
// max: 250,
|
||||
// interval: 50,
|
||||
// axisLabel: {
|
||||
// formatter: '{value} ml'
|
||||
// }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '缺陷率',
|
||||
// min: 0,
|
||||
// max: 25,
|
||||
// interval: 5,
|
||||
axisLabel: {
|
||||
formatter: '{value} %'
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '缺陷数量',
|
||||
type: 'bar',
|
||||
barWidth: '3%',
|
||||
data: listNumArr,
|
||||
// label: {
|
||||
// show: true, //开启显示
|
||||
// position: 'top', //在上方显示
|
||||
// // formatter: '{c}%',//显示百分号
|
||||
// textStyle: { //数值样式
|
||||
// color: 'black',//字体颜色
|
||||
// fontSize: 12//字体大小
|
||||
// }
|
||||
// }
|
||||
},
|
||||
{
|
||||
name: '缺陷率',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + '%';
|
||||
}
|
||||
},
|
||||
data: listRatioArr
|
||||
}
|
||||
]
|
||||
}
|
||||
myChart.clear()
|
||||
option && myChart.setOption(option);
|
||||
})
|
||||
},
|
||||
/** 获取搜索栏的产线列表 */
|
||||
async getDict() {
|
||||
// const res = await getProductList()
|
||||
// const result = await getWorkOrderList()
|
||||
const res = await this.$axios({
|
||||
url: '/extend/check-isra-standards/page',
|
||||
method: 'get',
|
||||
params: {
|
||||
pageSize: 100,
|
||||
pageNo:1
|
||||
}
|
||||
});
|
||||
// console.log(res)
|
||||
this.searchBarFormConfig[1].selectOptions = res.data.list
|
||||
await getPdList().then((res) => {
|
||||
// console.log(res);
|
||||
this.searchBarFormConfig[2].selectOptions = res.data;
|
||||
})
|
||||
// this.searchBarFormConfig[1].selectOptions = res.data.map((item) => {
|
||||
// return {
|
||||
// name: item.name,
|
||||
// id:item.id
|
||||
// }
|
||||
// })
|
||||
// this.searchBarFormConfig[0].selectOptions = result.data.map((item) => {
|
||||
// return {
|
||||
// name: item.name,
|
||||
// id: item.id
|
||||
// }
|
||||
// })
|
||||
},
|
||||
// getProductLineList() {
|
||||
// this.$axios('/base/production-line/listAll').then((response) => {
|
||||
// this.searchBarFormConfig[0].selectOptions = response.data.map(
|
||||
// (item) => {
|
||||
// return {
|
||||
// name: item.name,
|
||||
// id: item.id,
|
||||
// };
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
// },
|
||||
getList() {
|
||||
this.getDataList()
|
||||
},
|
||||
/** 查询列表 */
|
||||
async getDataList() {
|
||||
console.log('查询条件', this.queryParams);
|
||||
this.loading = true;
|
||||
// 执行查询
|
||||
const {
|
||||
data: { data, otherList, otherMap, nameData },
|
||||
} = await getQualityIsraPage(this.queryParams)
|
||||
console.log(this.queryParams);
|
||||
this.dynamicProps = this.filterNameData(nameData)
|
||||
this.list = this.filterData(data);
|
||||
},
|
||||
filterNameData(nameData) {
|
||||
const ndSet = new Set();
|
||||
nameData.forEach((nd) => {
|
||||
ndSet.add(nd.name);
|
||||
});
|
||||
return Array.from(ndSet.values())
|
||||
.sort()
|
||||
.map((name) => ({
|
||||
prop: name,
|
||||
label: name,
|
||||
}));
|
||||
},
|
||||
filterData(data) {
|
||||
return data.map((item) => {
|
||||
const { data: innerData } = item;
|
||||
const keyValuePairs = {};
|
||||
innerData.map((d) => {
|
||||
keyValuePairs[d.dynamicName] = d.dynamicValue;
|
||||
});
|
||||
return {
|
||||
// inspectionContent: item.inspectionContent,
|
||||
...keyValuePairs,
|
||||
sumNum: item.sumNum,
|
||||
// sumInput: item.sumInput,
|
||||
// productionName: item.productionName,
|
||||
checkType: item.checkType,
|
||||
// scrapRatio: item.scrapRatio,
|
||||
};
|
||||
});
|
||||
},
|
||||
/** 取消按钮 */
|
||||
handleSearchBarBtnClick(val) {
|
||||
console.log('11111', val)
|
||||
if (val.btnName === 'search') {
|
||||
this.queryParams.checkDiscard = (val?.checkDiscard === 0 || val?.checkDiscard === 1) ? val?.checkDiscard : undefined
|
||||
this.queryParams.lineName = val.lineName ? val.lineName : undefined
|
||||
this.queryParams.checkType = val.checkType ? val.checkType : undefined
|
||||
// this.queryParams.productionId = val.productionId ? val.productionId : undefined
|
||||
this.queryParams.startTime = val.checkTime ? val.checkTime[0] : undefined
|
||||
this.queryParams.endTime = val.checkTime ? val.checkTime[1] : undefined
|
||||
|
||||
this.getList()
|
||||
this.getData()
|
||||
}
|
||||
console.log(val);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.blue-title {
|
||||
position: relative;
|
||||
padding: 4px 0;
|
||||
padding-left: 12px;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
font-weight: 700;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 6px;
|
||||
height: 16px;
|
||||
width: 4px;
|
||||
border-radius: 1px;
|
||||
background: #0b58ff;
|
||||
}
|
||||
}
|
||||
</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>
|
||||
@@ -3157,6 +3157,11 @@
|
||||
"resolved" "https://registry.npmmirror.com/check-types/-/check-types-8.0.3.tgz"
|
||||
"version" "8.0.3"
|
||||
|
||||
"chinese-lunar@^0.1.4":
|
||||
"integrity" "sha512-E4seb9UZkSJtkm65Ry2ZLWTw5Z87DOyGcCePdg3ft7da342hnEliMtcDAPSn+YSo/o0xl1Egmhh671kxEJgY+g=="
|
||||
"resolved" "https://registry.npmmirror.com/chinese-lunar/-/chinese-lunar-0.1.4.tgz"
|
||||
"version" "0.1.4"
|
||||
|
||||
"chokidar@^2.1.8":
|
||||
"integrity" "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg=="
|
||||
"resolved" "https://registry.npmmirror.com/chokidar/-/chokidar-2.1.8.tgz"
|
||||
|
||||
Reference in New Issue
Block a user