feat: 新增多模块业务功能与页面
1. 新增轧辊产线共用mixins工具 2. 新增钢卷异常管理相关API、组件与页面 3. 新增成本管理相关模块API与CRUD页面 4. 新增多选组件MutiSelect
This commit is contained in:
19
ruoyi-ui/src/api/cost/coil.js
Normal file
19
ruoyi-ui/src/api/cost/coil.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
const BASE = '/wms/materialCoil'
|
||||
|
||||
export function getCoilHoardingStats(data) {
|
||||
return request({
|
||||
url: BASE + '/hoardingStatistics',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function listCoilHoardingDetail(query) {
|
||||
return request({
|
||||
url: BASE + '/listWithQrcode',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
44
ruoyi-ui/src/api/cost/item.js
Normal file
44
ruoyi-ui/src/api/cost/item.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询成本项目配置列表
|
||||
export function listItem(query) {
|
||||
return request({
|
||||
url: '/cost/item/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询成本项目配置详细
|
||||
export function getItem(itemId) {
|
||||
return request({
|
||||
url: '/cost/item/' + itemId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增成本项目配置
|
||||
export function addItem(data) {
|
||||
return request({
|
||||
url: '/cost/item',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改成本项目配置
|
||||
export function updateItem(data) {
|
||||
return request({
|
||||
url: '/cost/item',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除成本项目配置
|
||||
export function delItem(itemId) {
|
||||
return request({
|
||||
url: '/cost/item/' + itemId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
44
ruoyi-ui/src/api/cost/price.js
Normal file
44
ruoyi-ui/src/api/cost/price.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询成本单价历史列表
|
||||
export function listPrice(query) {
|
||||
return request({
|
||||
url: '/cost/price/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询成本单价历史详细
|
||||
export function getPrice(priceId) {
|
||||
return request({
|
||||
url: '/cost/price/' + priceId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增成本单价历史
|
||||
export function addPrice(data) {
|
||||
return request({
|
||||
url: '/cost/price',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改成本单价历史
|
||||
export function updatePrice(data) {
|
||||
return request({
|
||||
url: '/cost/price',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除成本单价历史
|
||||
export function delPrice(priceId) {
|
||||
return request({
|
||||
url: '/cost/price/' + priceId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
53
ruoyi-ui/src/api/cost/prodDetail.js
Normal file
53
ruoyi-ui/src/api/cost/prodDetail.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询生产成本明细列表
|
||||
export function listProdDetail(query) {
|
||||
return request({
|
||||
url: '/cost/prodDetail/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询生产成本明细详细
|
||||
export function getProdDetail(detailId) {
|
||||
return request({
|
||||
url: '/cost/prodDetail/' + detailId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增生产成本明细
|
||||
export function addProdDetail(data) {
|
||||
return request({
|
||||
url: '/cost/prodDetail',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改生产成本明细
|
||||
export function updateProdDetail(data) {
|
||||
return request({
|
||||
url: '/cost/prodDetail',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除生产成本明细
|
||||
export function delProdDetail(detailId) {
|
||||
return request({
|
||||
url: '/cost/prodDetail/' + detailId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 批量保存生产成本明细(先删除再插入)
|
||||
export function batchSaveProdDetail(data) {
|
||||
return request({
|
||||
url: '/cost/prodDetail/batch',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
44
ruoyi-ui/src/api/cost/prodMetric.js
Normal file
44
ruoyi-ui/src/api/cost/prodMetric.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询生产指标明细列表
|
||||
export function listProdMetric(query) {
|
||||
return request({
|
||||
url: '/cost/prodMetric/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询生产指标明细详细
|
||||
export function getProdMetric(metricId) {
|
||||
return request({
|
||||
url: '/cost/prodMetric/' + metricId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增生产指标明细
|
||||
export function addProdMetric(data) {
|
||||
return request({
|
||||
url: '/cost/prodMetric',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改生产指标明细
|
||||
export function updateProdMetric(data) {
|
||||
return request({
|
||||
url: '/cost/prodMetric',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除生产指标明细
|
||||
export function delProdMetric(metricId) {
|
||||
return request({
|
||||
url: '/cost/prodMetric/' + metricId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
53
ruoyi-ui/src/api/cost/prodReport.js
Normal file
53
ruoyi-ui/src/api/cost/prodReport.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询生产月报列表
|
||||
export function listProdReport(query) {
|
||||
return request({
|
||||
url: '/cost/prodReport/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询生产月报详细
|
||||
export function getProdReport(reportId) {
|
||||
return request({
|
||||
url: '/cost/prodReport/' + reportId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增生产月报
|
||||
export function addProdReport(data) {
|
||||
return request({
|
||||
url: '/cost/prodReport',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改生产月报
|
||||
export function updateProdReport(data) {
|
||||
return request({
|
||||
url: '/cost/prodReport',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除生产月报
|
||||
export function delProdReport(reportId) {
|
||||
return request({
|
||||
url: '/cost/prodReport/' + reportId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 复制生产月报
|
||||
export function copyProdReport(sourceId, data) {
|
||||
return request({
|
||||
url: '/cost/prodReport/copy/' + sourceId,
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
53
ruoyi-ui/src/api/mill/coilAbnormal.js
Normal file
53
ruoyi-ui/src/api/mill/coilAbnormal.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询钢卷异常信息列表
|
||||
export function listCoilAbnormal(query) {
|
||||
return request({
|
||||
url: '/mill/abnormal/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询钢卷异常信息详细
|
||||
export function getCoilAbnormal(abnormalId) {
|
||||
return request({
|
||||
url: '/mill/abnormal/' + abnormalId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增钢卷异常信息
|
||||
export function addCoilAbnormal(data) {
|
||||
return request({
|
||||
url: '/mill/abnormal',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改钢卷异常信息
|
||||
export function updateCoilAbnormal(data) {
|
||||
return request({
|
||||
url: '/mill/abnormal',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除钢卷异常信息
|
||||
export function delCoilAbnormal(abnormalId) {
|
||||
return request({
|
||||
url: '/mill/abnormal/' + abnormalId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 异常判级
|
||||
export function judgeAbnormalLevel(params) {
|
||||
return request({
|
||||
url: '/mill/abnormal/judge',
|
||||
method: 'put',
|
||||
params
|
||||
})
|
||||
}
|
||||
44
ruoyi-ui/src/api/mill/coilAbnormalRelation.js
Normal file
44
ruoyi-ui/src/api/mill/coilAbnormalRelation.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询二级-三级钢卷异常挂接/撤回关系列表
|
||||
export function listRelation(query) {
|
||||
return request({
|
||||
url: '/mill/relation/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询二级-三级钢卷异常挂接/撤回关系详细
|
||||
export function getRelation(relationId) {
|
||||
return request({
|
||||
url: '/mill/relation/' + relationId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增二级-三级钢卷异常挂接/撤回关系
|
||||
export function addRelation(data) {
|
||||
return request({
|
||||
url: '/mill/relation',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改二级-三级钢卷异常挂接/撤回关系
|
||||
export function updateRelation(data) {
|
||||
return request({
|
||||
url: '/mill/relation',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除二级-三级钢卷异常挂接/撤回关系
|
||||
export function delRelation(relationId) {
|
||||
return request({
|
||||
url: '/mill/relation/' + relationId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
62
ruoyi-ui/src/api/mill/rollChange.js
Normal file
62
ruoyi-ui/src/api/mill/rollChange.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询换辊记录分页列表(支持按产线、机架、类型、时间筛选)
|
||||
export function listRollChange(query) {
|
||||
return request({
|
||||
url: '/mes/rollChange/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询指定产线+机架当前在机轧辊(最近一次换辊记录)
|
||||
export function getCurrentRolls(lineId, standNo) {
|
||||
return request({
|
||||
url: '/mes/rollChange/current',
|
||||
method: 'get',
|
||||
params: { lineId, standNo }
|
||||
})
|
||||
}
|
||||
|
||||
// 查询指定产线各机架各辊位实时工作绩效(workLength/coilCount/totalWeight)
|
||||
export function getRollPerformance(lineId) {
|
||||
return request({
|
||||
url: '/mes/rollChange/performance',
|
||||
method: 'get',
|
||||
params: { lineId }
|
||||
})
|
||||
}
|
||||
|
||||
// 查询换辊记录详细
|
||||
export function getRollChange(changeId) {
|
||||
return request({
|
||||
url: '/mes/rollChange/' + changeId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增换辊记录(自动同步辊状态为 Online)
|
||||
export function addRollChange(data) {
|
||||
return request({
|
||||
url: '/mes/rollChange',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改换辊记录
|
||||
export function updateRollChange(data) {
|
||||
return request({
|
||||
url: '/mes/rollChange',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除换辊记录
|
||||
export function delRollChange(changeIds) {
|
||||
return request({
|
||||
url: '/mes/rollChange/' + changeIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
53
ruoyi-ui/src/api/mill/rollStandby.js
Normal file
53
ruoyi-ui/src/api/mill/rollStandby.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询指定产线+机架下批轧辊列表
|
||||
export function listRollStandby(lineId, standNo) {
|
||||
return request({
|
||||
url: '/mes/rollStandby/list',
|
||||
method: 'get',
|
||||
params: { lineId, standNo }
|
||||
})
|
||||
}
|
||||
|
||||
// 查询下批轧辊详细
|
||||
export function getRollStandby(standbyId) {
|
||||
return request({
|
||||
url: '/mes/rollStandby/' + standbyId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增下批轧辊(自动同步辊状态为 Standby)
|
||||
export function addRollStandby(data) {
|
||||
return request({
|
||||
url: '/mes/rollStandby',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改下批轧辊
|
||||
export function updateRollStandby(data) {
|
||||
return request({
|
||||
url: '/mes/rollStandby',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除单条下批轧辊(自动恢复辊状态为 Offline)
|
||||
export function delRollStandby(standbyId) {
|
||||
return request({
|
||||
url: '/mes/rollStandby/' + standbyId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 清空指定产线+机架全部下批轧辊
|
||||
export function clearRollStandby(lineId, standNo) {
|
||||
return request({
|
||||
url: '/mes/rollStandby/clear',
|
||||
method: 'delete',
|
||||
params: { lineId, standNo }
|
||||
})
|
||||
}
|
||||
168
ruoyi-ui/src/components/MutiSelect/index.vue
Normal file
168
ruoyi-ui/src/components/MutiSelect/index.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<div class="muti-select">
|
||||
<!-- 下拉选择模式 -->
|
||||
<div v-if="type === 'select'" class="select-container">
|
||||
<el-select
|
||||
v-model="innerValue"
|
||||
multiple
|
||||
:placeholder="placeholder"
|
||||
:filterable="filterable"
|
||||
:clearable="clearable"
|
||||
:allow-create="allowAdd"
|
||||
:disabled="disabled"
|
||||
:size="size"
|
||||
:collapse-tags="collapseTags"
|
||||
@change="handleChange"
|
||||
>
|
||||
<!-- 全选选项 -->
|
||||
<!-- <el-option
|
||||
v-if="showSelectAll && options.length > 0"
|
||||
key="selectAll"
|
||||
label="全选"
|
||||
value="selectAll"
|
||||
@click="toggleSelectAll"
|
||||
/> -->
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<!-- 复选框模式 -->
|
||||
<div v-else-if="type === 'checkbox'" class="checkbox-group">
|
||||
<el-checkbox-group v-model="innerValue" @change="handleCheckboxChange">
|
||||
<el-checkbox
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
:disabled="disabled"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<el-button
|
||||
v-if="showSelectAll && options.length > 0"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="toggleSelectAll"
|
||||
>
|
||||
{{ isAllSelected ? '取消全选' : '全选' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- v-model 绑定逗号分隔的字符串,可以 props 配置是否允许新增 -->
|
||||
<script>
|
||||
export default {
|
||||
name: 'MutiSelect',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
allowAdd: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'select' // select or checkbox
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
filterable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'default' // large, default, small
|
||||
},
|
||||
showSelectAll: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
collapseTags: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
// 计算属性捕获实现双向绑定
|
||||
computed: {
|
||||
innerValue: {
|
||||
get() {
|
||||
if (!this.value) {
|
||||
return [];
|
||||
}
|
||||
return this.value?.split(',');
|
||||
},
|
||||
set(val) {
|
||||
const newValue = val?.join(',') ?? '';
|
||||
this.$emit('input', newValue);
|
||||
this.$emit('change', newValue);
|
||||
}
|
||||
},
|
||||
// 是否全选
|
||||
isAllSelected() {
|
||||
return this.options.length > 0 && this.innerValue.length === this.options.length;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 处理选择变化
|
||||
handleChange(val) {
|
||||
// 过滤掉 'selectAll' 选项
|
||||
const filteredVal = val.filter(item => item !== 'selectAll');
|
||||
this.$emit('change', filteredVal.join(','));
|
||||
},
|
||||
// 处理复选框变化
|
||||
handleCheckboxChange(val) {
|
||||
const newValue = val.join(',');
|
||||
this.$emit('input', newValue);
|
||||
this.$emit('change', newValue);
|
||||
},
|
||||
// 切换全选/取消全选
|
||||
toggleSelectAll() {
|
||||
if (this.isAllSelected) {
|
||||
this.innerValue = [];
|
||||
} else {
|
||||
this.innerValue = this.options.map(item => item.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.muti-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.checkbox-group .el-checkbox {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
749
ruoyi-ui/src/views/cost/comprehensive.vue
Normal file
749
ruoyi-ui/src/views/cost/comprehensive.vue
Normal file
@@ -0,0 +1,749 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="report-tab-bar">
|
||||
<div class="report-tabs">
|
||||
<span v-for="r in tabs" :key="r.reportId"
|
||||
:class="['report-tab', { active: activeReport && activeReport.reportId === r.reportId }]"
|
||||
@click="enter(r)">{{ r.reportTitle }}</span>
|
||||
</div>
|
||||
<el-button size="mini" icon="el-icon-setting" @click="openConfig">配置</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="!activeReport" class="empty-hint">请在上方选择报表,或点击"配置"管理报表</div>
|
||||
|
||||
<template v-if="activeReport">
|
||||
<el-card class="mb8">
|
||||
<div slot="header" class="entry-header">
|
||||
<span class="entry-title">{{ activeReport.reportTitle }}</span>
|
||||
<span class="entry-meta">{{ parseTime(activeReport.reportDate,'{y}-{m}-{d}') }} 投入{{ activeReport.inputWeight }}t 产出{{ activeReport.outputWeight }}t</span>
|
||||
<el-button type="primary" size="mini" style="float:right;margin-left:8px" @click="saveGrid" :loading="saving">保存</el-button>
|
||||
<el-button size="mini" style="float:right;margin-left:8px" @click="openColCfg">列配置</el-button>
|
||||
<span style="float:right;margin-right:12px;font-size:12px;color:#606266;display:flex;align-items:center">
|
||||
<span style="margin-right:4px">{{ inputMode ? '录入' : '查看' }}</span>
|
||||
<el-switch v-model="inputMode" size="small" />
|
||||
</span>
|
||||
</div>
|
||||
<el-alert :title="'已配置'+allCols.length+'个列'" type="info" :closable="false" show-icon style="margin-bottom:8px" />
|
||||
<el-table v-loading="gridLoading" :data="gridRows" border stripe size="mini" style="width:100%" :header-cell-style="headerStyle" :key="'tbl-'+inputMode">
|
||||
<el-table-column label="日期" width="135" fixed>
|
||||
<template slot-scope="s"><el-date-picker v-model="s.row.detailDate" type="date" value-format="yyyy-MM-dd" size="mini" style="width:124px" @change="sortGrid" /></template>
|
||||
</el-table-column>
|
||||
<template v-for="col in displayCols">
|
||||
<el-table-column v-if="col.$type==='detail' && !col.isShift" :key="'d'+col.itemId" :label="col.itemName+(col.unit?'('+col.unit+')':'')" width="105" align="center">
|
||||
<template slot-scope="s">
|
||||
<el-input v-model="s.row['q'+col.itemId]" size="mini" @input="recalcAll">
|
||||
<i slot="suffix" v-if="col.queryCondition" :class="autoLoading[col.itemId]?'el-icon-loading':'el-icon-refresh'" style="cursor:pointer;font-size:13px;line-height:24px;color:#409eff" @click.stop="fetchAutoData(col, s.row)" />
|
||||
</el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-else-if="col.$type==='detail' && col.isShift" :key="'ds'+col.itemId" :label="col.itemName+(col.unit?'('+col.unit+')':'')" width="120" align="center">
|
||||
<template slot-scope="s">
|
||||
<div class="shift-cell"><span class="shift-tag">甲</span><el-input v-model="s.row['q'+col.itemId+'_1']" size="mini" class="shift-input" @input="recalcAll"><i slot="suffix" v-if="col.queryCondition" :class="autoLoading[col.itemId]?'el-icon-loading':'el-icon-refresh'" style="cursor:pointer;font-size:12px;line-height:24px;color:#409eff" @click.stop="fetchAutoData(col, s.row, '1')" /></el-input></div>
|
||||
<div class="shift-cell"><span class="shift-tag">乙</span><el-input v-model="s.row['q'+col.itemId+'_2']" size="mini" class="shift-input" @input="recalcAll"><i slot="suffix" v-if="col.queryCondition" :class="autoLoading[col.itemId]?'el-icon-loading':'el-icon-refresh'" style="cursor:pointer;font-size:12px;line-height:24px;color:#409eff" @click.stop="fetchAutoData(col, s.row, '2')" /></el-input></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-else-if="col.$type==='metric' && !col.isShift" :key="'m'+col.mIdx" :label="col.metricName+(col.unit?'('+col.unit+')':'')" width="85" align="center">
|
||||
<template slot-scope="s">{{ s.row['mv'+col.mIdx]!=null ? s.row['mv'+col.mIdx] : '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-else-if="col.$type==='metric' && col.isShift" :key="'ms'+col.mIdx" :label="col.metricName+(col.unit?'('+col.unit+')':'')" width="95" align="center">
|
||||
<template slot-scope="s">
|
||||
<div class="shift-metric">甲 {{ s.row['mv'+col.mIdx+'_1']!=null ? s.row['mv'+col.mIdx+'_1'] : '-' }}</div>
|
||||
<div class="shift-metric">乙 {{ s.row['mv'+col.mIdx+'_2']!=null ? s.row['mv'+col.mIdx+'_2'] : '-' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<el-table-column label="操作" width="55" fixed="right" align="center">
|
||||
<template slot-scope="s"><el-button size="mini" type="text" style="padding:0" @click="gridRows.splice(s.$index,1)">删除</el-button></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="margin-top:8px;text-align:center"><el-button type="default" icon="el-icon-plus" size="mini" @click="gridRows.push({detailDate:''})">添加日期行</el-button></div>
|
||||
</el-card>
|
||||
|
||||
<!-- Column config -->
|
||||
<el-dialog title="列配置" :visible.sync="colOpen" width="880px" append-to-body top="5vh">
|
||||
<div style="margin-bottom:8px;display:flex;justify-content:space-between;align-items:center">
|
||||
<span style="color:#999;font-size:12px">共 {{ allCols.length }} 列</span>
|
||||
<div>
|
||||
<el-button size="mini" type="danger" :disabled="!selCol.length" @click="batchDelCol">删除</el-button>
|
||||
<el-button type="primary" size="mini" @click="showAddDetail=true">+ 明细列</el-button>
|
||||
<el-button size="mini" type="success" @click="openMetricPicker">+ 指标列</el-button>
|
||||
<el-button size="mini" plain @click="openMetricMgr">指标管理</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="allCols" border stripe size="mini" highlight-current-row @dragover.native.prevent @drop.native="onNativeDrop" @current-change="curIdx = allCols.indexOf($event)" @selection-change="selCol=$event">
|
||||
<el-table-column type="selection" width="40" />
|
||||
<el-table-column label="序号" type="index" width="50" align="center" />
|
||||
<el-table-column label="类型" width="60" align="center">
|
||||
<template slot-scope="s">
|
||||
<el-tag v-if="s.row.$type==='detail'" type="primary" size="mini">明细</el-tag>
|
||||
<el-tag v-else type="success" size="mini">指标</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" width="140">
|
||||
<template slot-scope="s">{{ s.row.$type==='detail' ? (s.row.itemName||s.row.itemCode) : (s.row.metricName||'(空)') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="公式" min-width="180">
|
||||
<template slot-scope="s"><span v-if="s.row.$type==='metric'" style="font-size:11px;color:#666">{{ s.row.metricFormula }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单位" width="55" align="center">
|
||||
<template slot-scope="s">{{ s.row.unit }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="表头色" width="70" align="center">
|
||||
<template slot-scope="s"><el-color-picker v-model="s.row.color" size="mini" :predefine="['#409eff','#67c23a','#e6a23c','#f56c6c','#909399']" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分班次" width="70" align="center">
|
||||
<template slot-scope="s"><el-checkbox v-model="s.row.isShift" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="175" align="center">
|
||||
<template slot-scope="s">
|
||||
<span style="display:inline-flex;align-items:center">
|
||||
<span class="drag-handle" title="拖拽排序"
|
||||
:draggable="true"
|
||||
@dragstart.stop="onDragStart(s.$index)"
|
||||
@dragend="onDragEnd">
|
||||
<i class="el-icon-rank" />
|
||||
</span>
|
||||
<el-button size="mini" type="text" icon="el-icon-d-arrow-left" :disabled="s.$index===0" title="置于最上" @click="moveColToEdge(s.$index,'top')" />
|
||||
<el-button size="mini" type="text" icon="el-icon-top" :disabled="s.$index===0" @click="moveCol(s.$index,-1)" />
|
||||
<el-button size="mini" type="text" icon="el-icon-bottom" :disabled="s.$index===allCols.length-1" @click="moveCol(s.$index,1)" />
|
||||
<el-button size="mini" type="text" icon="el-icon-d-arrow-right" :disabled="s.$index===allCols.length-1" title="置于最下" @click="moveColToEdge(s.$index,'bottom')" />
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="allCols.splice(s.$index,1)" />
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div slot="footer"><el-button type="primary" @click="saveColCfg" :loading="colSaving">保存配置</el-button><el-button @click="colOpen=false">取消</el-button></div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- Add detail -->
|
||||
<el-dialog title="添加明细列" :visible.sync="showAddDetail" width="550px" append-to-body>
|
||||
<el-table :data="availableItems" border stripe size="mini" @selection-change="selAdd=$event">
|
||||
<el-table-column type="selection" width="45" />
|
||||
<el-table-column label="编码" prop="itemCode" width="120" />
|
||||
<el-table-column label="名称" prop="itemName" />
|
||||
<el-table-column label="单位" prop="unit" width="70" />
|
||||
</el-table>
|
||||
<div slot="footer">
|
||||
<el-button type="primary" :disabled="!selAdd.length" @click="batchAddDetailCols">确 定</el-button>
|
||||
<el-button @click="showAddDetail=false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- Pick metric -->
|
||||
<el-dialog title="选择指标列" :visible.sync="metricPickOpen" width="600px" append-to-body>
|
||||
<el-table :data="metricPickList" border stripe size="mini" @selection-change="selMp=$event">
|
||||
<el-table-column type="selection" width="45" />
|
||||
<el-table-column label="名称" prop="metricName" width="150" />
|
||||
<el-table-column label="公式" prop="metricFormula" min-width="200" />
|
||||
<el-table-column label="单位" prop="unit" width="70" />
|
||||
</el-table>
|
||||
<div slot="footer">
|
||||
<el-button type="primary" :disabled="!selMp.length" @click="doPickMetric">确 定</el-button>
|
||||
<el-button @click="metricPickOpen=false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- Metric management -->
|
||||
<el-dialog title="指标管理" :visible.sync="mgrOpen" width="750px" top="5vh" append-to-body>
|
||||
<div style="margin-bottom:8px">
|
||||
<el-button type="primary" size="mini" @click="addMetricDef">新增指标</el-button>
|
||||
</div>
|
||||
<el-table :data="mgrList" border stripe size="mini">
|
||||
<el-table-column label="名称" prop="metricName" width="150" />
|
||||
<el-table-column label="公式" prop="metricFormula" min-width="200" />
|
||||
<el-table-column label="单位" prop="remark" width="70" />
|
||||
<el-table-column label="操作" width="100">
|
||||
<template slot-scope="s">
|
||||
<el-button size="mini" type="text" @click="editMetricDef(s.row)">编辑</el-button>
|
||||
<el-button size="mini" type="text" style="color:#f56c6c" @click="delMetricDef(s.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog :title="defTitle" :visible.sync="defOpen" width="480px" append-to-body>
|
||||
<el-form :model="defForm" label-width="80px" size="small">
|
||||
<el-form-item label="指标名称"><el-input v-model="defForm.metricName" /></el-form-item>
|
||||
<el-form-item label="公式"><el-input v-model="defForm.metricFormula" type="textarea" :rows="3" /></el-form-item>
|
||||
<div class="formula-vars" v-if="allCols.length">
|
||||
<span class="vars-label">变量:</span>
|
||||
<template v-for="c in allCols.filter(x=>x.$type==='detail')">
|
||||
<el-tag :key="'v'+c.itemId" size="mini" class="vars-tag" @click="defForm.metricFormula=(defForm.metricFormula||'')+'@{'+c.itemCode+'}'">{{ c.itemCode }}</el-tag>
|
||||
</template>
|
||||
<el-tag size="mini" class="vars-tag var-sys" @click="defForm.metricFormula=(defForm.metricFormula||'')+'input_weight'">input_weight</el-tag>
|
||||
<el-tag size="mini" class="vars-tag var-sys" @click="defForm.metricFormula=(defForm.metricFormula||'')+'output_weight'">output_weight</el-tag>
|
||||
<template v-for="c in allCols.filter(x=>x.$type==='metric'&&x.metricName)">
|
||||
<el-tag :key="'v'+c.metricName" size="mini" class="vars-tag var-mtr" @click="defForm.metricFormula=(defForm.metricFormula||'')+'@{'+c.metricName+'}'">{{ c.metricName }}</el-tag>
|
||||
</template>
|
||||
</div>
|
||||
<el-form-item label="单位"><el-input v-model="defForm.unit" placeholder="如 %" /></el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button type="primary" @click="submitMetricDef">确 定</el-button>
|
||||
<el-button @click="defOpen=false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-dialog>
|
||||
|
||||
<!-- Copy config -->
|
||||
<el-dialog title="从已有报表复制配置" :visible.sync="copyCfgOpen" width="550px" append-to-body>
|
||||
<el-table :data="copyReports" border stripe size="mini" highlight-current-row @current-change="copySrc=$event">
|
||||
<el-table-column label="报表标题" prop="reportTitle" />
|
||||
<el-table-column label="日期" width="110"><template slot-scope="s">{{ parseTime(s.row.reportDate,'{y}-{m}-{d}') }}</template></el-table-column>
|
||||
</el-table>
|
||||
<div slot="footer">
|
||||
<el-button type="primary" :disabled="!copySrc" @click="doCopyCfg">确认复制</el-button>
|
||||
<el-button @click="copyCfgOpen=false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<!-- Report management -->
|
||||
<el-dialog title="报表管理" :visible.sync="configOpen" width="900px" top="5vh" append-to-body>
|
||||
<el-form :model="q" ref="qf" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
||||
<el-form-item label="报表标题" prop="reportTitle"><el-input v-model="q.reportTitle" placeholder="请输入" clearable @keyup.enter.native="search" /></el-form-item>
|
||||
<el-form-item label="报表日期" prop="reportDate"><el-date-picker v-model="q.reportDate" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" clearable /></el-form-item>
|
||||
<el-form-item><el-button type="primary" icon="el-icon-search" size="mini" @click="search">搜索</el-button><el-button icon="el-icon-refresh" size="mini" @click="resetQ">重置</el-button></el-form-item>
|
||||
</el-form>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5"><el-button type="primary" plain icon="el-icon-plus" size="mini" @click="addRp">新增</el-button></el-col>
|
||||
<el-col :span="1.5"><el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="sel!==1" @click="editRp">修改</el-button></el-col>
|
||||
<el-col :span="1.5"><el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="sel<1" @click="delRp">删除</el-button></el-col>
|
||||
<el-col :span="1.5"><el-button type="warning" plain icon="el-icon-document-copy" size="mini" :disabled="sel!==1" @click="openCopyRp">复制</el-button></el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
<el-table v-loading="loading" :data="list" @selection-change="s=>{sel=s.length;selIds=s.map(r=>r.reportId)}" ref="rt">
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column label="报表标题" prop="reportTitle" />
|
||||
<el-table-column label="日期" width="120"><template slot-scope="s">{{ parseTime(s.row.reportDate,'{y}-{m}-{d}') }}</template></el-table-column>
|
||||
<el-table-column label="操作" width="180" align="center">
|
||||
<template slot-scope="s">
|
||||
<el-button size="mini" type="text" style="padding:0" @click="editRp(s.row)">修改</el-button>
|
||||
<el-button size="mini" type="text" style="padding:0" @click="copyInlineRp(s.row)">复制</el-button>
|
||||
<el-button size="mini" type="text" style="padding:0;color:#f56c6c" @click="delRp(s.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="q.pageNum" :limit.sync="q.pageSize" @pagination="getList" />
|
||||
|
||||
<el-dialog :title="rpTitle" :visible.sync="rpOpen" width="500px" append-to-body>
|
||||
<el-form ref="rpf" :model="rpForm" :rules="{reportTitle:[{required:true,message:'请输入',trigger:'blur'}]}" label-width="100px">
|
||||
<el-form-item label="报表标题" prop="reportTitle"><el-input v-model="rpForm.reportTitle" placeholder="请输入报表标题" /></el-form-item>
|
||||
<el-form-item label="报表日期" prop="reportDate"><el-date-picker v-model="rpForm.reportDate" type="date" placeholder="选择日期" clearable value-format="yyyy-MM-dd" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="备注" prop="remark"><el-input v-model="rpForm.remark" type="textarea" placeholder="请输入备注" /></el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer"><el-button :loading="rpBtnLoading" type="primary" @click="submitRp">确 定</el-button><el-button @click="rpOpen=false">取 消</el-button></div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 复制报表弹窗 -->
|
||||
<el-dialog title="复制报表" :visible.sync="copyRpOpen" width="500px" append-to-body>
|
||||
<el-form :model="copyRpForm" label-width="100px" size="small">
|
||||
<el-form-item label="报表标题"><el-input v-model="copyRpForm.reportTitle" placeholder="请输入报表标题" /></el-form-item>
|
||||
<el-form-item label="报表日期"><el-date-picker v-model="copyRpForm.reportDate" type="date" placeholder="选择日期" clearable value-format="yyyy-MM-dd" style="width:100%" /></el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button type="primary" @click="doCopyRp">确 定</el-button>
|
||||
<el-button @click="copyRpOpen=false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listProdReport, getProdReport, addProdReport, updateProdReport, delProdReport, copyProdReport } from "@/api/cost/prodReport"
|
||||
import { listProdDetail, batchSaveProdDetail } from "@/api/cost/prodDetail"
|
||||
import { listProdMetric, addProdMetric, updateProdMetric, delProdMetric, getProdMetric } from "@/api/cost/prodMetric"
|
||||
import { listItem } from "@/api/cost/item"
|
||||
|
||||
function parseDateRange(detailDate) {
|
||||
const d = (detailDate || '').slice(0, 10)
|
||||
return {
|
||||
startTime: d + ' 00:00:00',
|
||||
endTime: d + ' 23:59:59'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动查询处理器注册表。
|
||||
* key: item.category, value: async (queryCondition, row, col, report, shift) => fetchedValue
|
||||
*/
|
||||
const queryHandlers = {}
|
||||
export function registerQueryHandler(category, handler) {
|
||||
queryHandlers[category] = handler
|
||||
}
|
||||
|
||||
const teamMap = { '1': '甲', '2': '乙' }
|
||||
|
||||
registerQueryHandler('原料', async (queryCondition, row, col, report, shift) => {
|
||||
if (!row.detailDate) return null
|
||||
const { startTime, endTime } = parseDateRange(row.detailDate)
|
||||
const res = await listLightPendingAction({ actionStatus: 2, actionTypes: queryCondition, startTime, endTime, pageSize: 99999 })
|
||||
const items = Array.isArray(res.data) ? res.data : (res.rows || [])
|
||||
const ids = [...new Set(items.map(i => i.coilId).filter(Boolean))]
|
||||
if (!ids.length) return null
|
||||
const params = { coilIds: ids.join(',') }
|
||||
if (shift && teamMap[shift]) params.team = teamMap[shift]
|
||||
const stat = await getCoilStatisticsList(params)
|
||||
const net = stat.data && stat.data.total_net_weight
|
||||
return net != null ? net : null
|
||||
})
|
||||
|
||||
registerQueryHandler('产出', async (queryCondition, row, col, report, shift) => {
|
||||
if (!row.detailDate) return null
|
||||
const { startTime, endTime } = parseDateRange(row.detailDate)
|
||||
const res = await listLightPendingAction({ actionStatus: 2, actionTypes: queryCondition, startTime, endTime, pageSize: 99999 })
|
||||
const items = Array.isArray(res.data) ? res.data : (res.rows || [])
|
||||
const ids = []
|
||||
for (const i of items) {
|
||||
if (i.processedCoilIds) {
|
||||
i.processedCoilIds.split(',').forEach(id => { id = id.trim(); if (id) ids.push(id) })
|
||||
}
|
||||
}
|
||||
if (!ids.length) return null
|
||||
const params = { coilIds: [...new Set(ids)].join(',') }
|
||||
if (shift && teamMap[shift]) params.team = teamMap[shift]
|
||||
const stat = await getCoilStatisticsList(params)
|
||||
const net = stat.data && stat.data.total_net_weight
|
||||
return net != null ? net : null
|
||||
})
|
||||
|
||||
registerQueryHandler('辅料', async (queryCondition, row, col, report, shift) => {
|
||||
if (!row.detailDate) return null
|
||||
const d = (row.detailDate || '').slice(0, 10)
|
||||
const res = await listAuxiliaryConsume({ recordDate: d, typeId: queryCondition, pageSize: 9999 })
|
||||
const items = res.rows || []
|
||||
const total = items.reduce((s, item) => s + (parseFloat(item.consume) || 0), 0)
|
||||
if (col.isShift) {
|
||||
const half = total / 2
|
||||
return [half, half]
|
||||
}
|
||||
return total || null
|
||||
})
|
||||
|
||||
registerQueryHandler('轧辊', async (queryCondition, row, col, report, shift) => {
|
||||
if (!row.detailDate) return null
|
||||
const d = (row.detailDate || '').slice(0, 10)
|
||||
const params = { beginTime: d + ' 00:00:00', endTime: d + ' 23:59:59', rollType: queryCondition }
|
||||
if (shift && teamMap[shift]) params.team = teamMap[shift] + '班'
|
||||
const res = await listRollGrindAll(params)
|
||||
const items = res.data || []
|
||||
if (!items.length) return null
|
||||
let total = 0
|
||||
items.forEach(item => { total += parseFloat(item.grindAmount) || 0 })
|
||||
return total || null
|
||||
})
|
||||
|
||||
export default {
|
||||
name: "CostComprehensive",
|
||||
data() {
|
||||
return {
|
||||
loading: false, list: [], tabs: [], total: 0, sel: 0, selIds: [], showSearch: true,
|
||||
q: { pageNum: 1, pageSize: 10, reportTitle: undefined, reportDate: undefined },
|
||||
rpOpen: false, rpTitle: "", rpBtnLoading: false, rpForm: {},
|
||||
copyRpOpen: false, copyRpForm: {},
|
||||
activeReport: null, gridLoading: false, gridRows: [], saving: false,
|
||||
allItems: [], allCols: [],
|
||||
colOpen: false, colSaving: false,
|
||||
showAddDetail: false, selAdd: [], selCol: [], curIdx: -1, dragIdx: -1,
|
||||
metricPickOpen: false, metricPickList: [], selMp: [],
|
||||
mgrOpen: false, mgrList: [], defOpen: false, defTitle: '', defForm: {},
|
||||
copyCfgOpen: false, copyReports: [], copySrc: null,
|
||||
configOpen: false,
|
||||
autoLoading: {},
|
||||
inputMode: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
availableItems() {
|
||||
const used = new Set(this.allCols.filter(c => c.$type === 'detail').map(c => String(c.itemId)))
|
||||
return this.allItems.filter(i => !used.has(String(i.itemId)))
|
||||
},
|
||||
displayCols() {
|
||||
if (!this.inputMode) return this.allCols
|
||||
return [...this.allCols.filter(c => c.$type === 'detail'), ...this.allCols.filter(c => c.$type === 'metric')]
|
||||
},
|
||||
headerStyle() {
|
||||
return ({ column }) => {
|
||||
if (!column || !column.label) return {}
|
||||
const col = this.allCols.find(c => {
|
||||
if (c.$type === 'detail') return column.label.startsWith(c.itemName || c.itemCode)
|
||||
if (c.$type === 'metric') return column.label.startsWith(c.metricName)
|
||||
return false
|
||||
})
|
||||
return col && col.color ? { background: col.color, color: '#fff' } : {}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: { configOpen(v) { if (!v) this.rpOpen = false } },
|
||||
created() {
|
||||
this.getTabList()
|
||||
this.loadItems()
|
||||
},
|
||||
methods: {
|
||||
/* report */
|
||||
getList() {
|
||||
this.loading = true
|
||||
const params = { ...this.q }
|
||||
listProdReport(params).then(r=>{this.list=r.rows;this.total=r.total}).finally(()=>this.loading=false)
|
||||
},
|
||||
getTabList() {
|
||||
const params = { pageNum: 1, pageSize: 9999 }
|
||||
listProdReport(params).then(r => { this.tabs = r.rows || [] })
|
||||
},
|
||||
search() { this.q.pageNum = 1; this.getList() },
|
||||
resetQ() { this.resetForm("qf"); this.search() },
|
||||
addRp() { this.rpForm = {}; this.rpTitle = "新增"; this.rpOpen = true },
|
||||
editRp(row) {
|
||||
const id = (row&&row.reportId)||this.selIds[0]; if(!id)return
|
||||
getProdReport(id).then(r=>{
|
||||
const d = r.data || {}
|
||||
this.rpForm = d; this.rpTitle = "修改"; this.rpOpen = true
|
||||
})
|
||||
},
|
||||
submitRp() {
|
||||
this.$refs.rpf.validate(v=>{if(!v)return;this.rpBtnLoading=true;const fn=this.rpForm.reportId?updateProdReport:addProdReport;fn(this.rpForm).then(()=>{
|
||||
this.$modal.msgSuccess("成功"); this.rpOpen = false
|
||||
if (this.activeReport && this.activeReport.reportId === this.rpForm.reportId) {
|
||||
Object.assign(this.activeReport, { reportTitle: this.rpForm.reportTitle, reportDate: this.rpForm.reportDate, inputWeight: this.rpForm.inputWeight, outputWeight: this.rpForm.outputWeight })
|
||||
}
|
||||
this.getTabList(); this.getList()
|
||||
}).finally(()=>this.rpBtnLoading=false)})
|
||||
},
|
||||
delRp(row) {
|
||||
const ids=(row&&row.reportId)?[row.reportId]:this.selIds;if(!ids.length)return
|
||||
this.$modal.confirm("确认删除?").then(()=>delProdReport(ids.join(','))).then(()=>{
|
||||
if (this.activeReport && ids.includes(this.activeReport.reportId)) { this.activeReport = null; this.gridRows = []; this.allCols = [] }
|
||||
this.getTabList(); this.getList(); this.$modal.msgSuccess("已删除")
|
||||
})
|
||||
},
|
||||
openConfig() { this.configOpen = true; this.getList() },
|
||||
openCopyRp() {
|
||||
const row = this.list.find(r => r.reportId === this.selIds[0])
|
||||
this.copyRpForm = { reportId: this.selIds[0], reportTitle: (row ? row.reportTitle : '') + '-副本', reportDate: row ? row.reportDate : undefined }
|
||||
this.copyRpOpen = true
|
||||
},
|
||||
copyInlineRp(row) {
|
||||
this.copyRpForm = { reportId: row.reportId, reportTitle: row.reportTitle + '-副本', reportDate: row.reportDate }
|
||||
this.copyRpOpen = true
|
||||
},
|
||||
async doCopyRp() {
|
||||
const sid = this.copyRpForm.reportId
|
||||
if (!sid) return
|
||||
await copyProdReport(sid, { reportTitle: this.copyRpForm.reportTitle, reportDate: this.copyRpForm.reportDate })
|
||||
this.copyRpOpen = false
|
||||
this.$modal.msgSuccess('复制成功')
|
||||
this.getTabList(); this.getList()
|
||||
},
|
||||
|
||||
/* column config */
|
||||
async openColCfg() { await this.loadItems(); await this.restoreAllCols(); this.colOpen = true },
|
||||
moveCol(idx, dir) { const arr = this.allCols; const t = idx + dir; if (t >= 0 && t < arr.length) { const item = arr.splice(idx, 1)[0]; arr.splice(t, 0, item) } },
|
||||
moveColToEdge(idx, edge) { const arr = this.allCols; const item = arr.splice(idx, 1)[0]; edge === 'top' ? arr.unshift(item) : arr.push(item) },
|
||||
onDragStart(idx) {
|
||||
this.dragIdx = idx
|
||||
},
|
||||
onDragEnd() {
|
||||
this.dragIdx = -1
|
||||
},
|
||||
onNativeDrop(e) {
|
||||
if (this.dragIdx < 0) return
|
||||
const tr = e.target.closest('tr')
|
||||
if (!tr) return
|
||||
const rows = Array.from(tr.parentElement.querySelectorAll('tr'))
|
||||
const targetIdx = rows.indexOf(tr)
|
||||
if (targetIdx >= 0) this.onDragDrop(targetIdx)
|
||||
},
|
||||
onDragDrop(targetIdx) {
|
||||
if (this.dragIdx < 0 || targetIdx < 0 || this.dragIdx === targetIdx) return
|
||||
const arr = this.allCols
|
||||
const item = arr.splice(this.dragIdx, 1)[0]
|
||||
const insertAt = this.dragIdx < targetIdx ? targetIdx - 1 : targetIdx
|
||||
arr.splice(insertAt, 0, item)
|
||||
this.dragIdx = -1
|
||||
this.$forceUpdate()
|
||||
},
|
||||
batchAddDetailCols() {
|
||||
this.selAdd.forEach(item => {
|
||||
if (!this.allCols.find(c => c.$type === 'detail' && String(c.itemId) === String(item.itemId)))
|
||||
this.allCols.push({ $type: 'detail', itemId: item.itemId, itemCode: item.itemCode, itemName: item.itemName, unit: item.unit, isShift: false, color: null, queryCondition: item.queryCondition, category: item.category })
|
||||
})
|
||||
this.showAddDetail = false; this.selAdd = []
|
||||
},
|
||||
batchDelCol() {
|
||||
const set = new Set(this.selCol.map(r => r))
|
||||
this.allCols = this.allCols.filter(c => !set.has(c))
|
||||
this.selCol = []; this.curIdx = -1
|
||||
},
|
||||
/* metric picker */
|
||||
async openMetricPicker() {
|
||||
await this.loadAllMetrics(this.activeReport.reportId)
|
||||
const used = new Set(this.allCols.filter(c => c.$type === 'metric' && c.metricId).map(c => String(c.metricId)))
|
||||
this.metricPickList = (this._allMetricDefs || []).filter(m => !used.has(String(m.metricId)))
|
||||
this.selMp = []; this.metricPickOpen = true
|
||||
},
|
||||
doPickMetric() {
|
||||
this.selMp.forEach(m => {
|
||||
this.allCols.push({ $type: 'metric', metricId: m.metricId, metricName: m.metricName, metricFormula: m.metricFormula, unit: m.remark||'', isShift: false, color: null })
|
||||
})
|
||||
this.metricPickOpen = false
|
||||
},
|
||||
/* metric management */
|
||||
async openMetricMgr() {
|
||||
await this.loadAllMetrics(this.activeReport.reportId)
|
||||
this.mgrList = this._allMetricDefs || []
|
||||
this.mgrOpen = true
|
||||
},
|
||||
addMetricDef() { this.defForm = { metricId: null, metricName: '', metricFormula: '', unit: '' }; this.defTitle = '新增指标'; this.defOpen = true },
|
||||
editMetricDef(row) { this.defForm = { metricId: row.metricId, metricName: row.metricName, metricFormula: row.metricFormula, unit: row.remark||'' }; this.defTitle = '编辑指标'; this.defOpen = true },
|
||||
async submitMetricDef() {
|
||||
const f = this.defForm
|
||||
if (!f.metricName) { this.$modal.msgWarning('请输入指标名称'); return }
|
||||
if (f.metricId) {
|
||||
await updateProdMetric({ metricId: f.metricId, metricName: f.metricName, metricFormula: f.metricFormula, remark: f.unit })
|
||||
} else {
|
||||
await addProdMetric({ reportId: this.activeReport.reportId, metricCode: f.metricName, metricName: f.metricName, metricFormula: f.metricFormula, metricValue: 0, remark: f.unit || '' })
|
||||
}
|
||||
this.defOpen = false; this.$modal.msgSuccess('保存成功')
|
||||
await this.openMetricMgr()
|
||||
},
|
||||
async delMetricDef(row) {
|
||||
this.$modal.confirm('确认删除指标 "' + row.metricName + '"?').then(async () => {
|
||||
await delProdMetric(row.metricId)
|
||||
await this.openMetricMgr()
|
||||
this.$modal.msgSuccess('已删除')
|
||||
})
|
||||
},
|
||||
|
||||
async saveColCfg() {
|
||||
const rid = this.activeReport.reportId; this.colSaving = true
|
||||
try {
|
||||
const metricCols = this.allCols.filter(c => c.$type === 'metric')
|
||||
for (const m of metricCols) {
|
||||
if (!m.metricName) { this.$modal.msgWarning('存在空指标列'); return }
|
||||
if (m.metricFormula) {
|
||||
const testF = m.metricFormula.replace(/@\{[^}]+\}/g, '1').replace(/input_weight|output_weight/g, '1')
|
||||
if (this.evalF(testF) === null) { this.$modal.msgError('指标 "' + m.metricName + '" 公式无效'); return }
|
||||
}
|
||||
}
|
||||
// ensure metric definitions exist in DB for all metric columns before saving config
|
||||
for (const mc of metricCols) {
|
||||
if (!mc.metricId) {
|
||||
const r = await addProdMetric({ reportId: rid, metricCode: mc.metricName, metricName: mc.metricName, metricFormula: mc.metricFormula || '', metricValue: 0, remark: mc.unit || '' })
|
||||
mc.metricId = r.data && r.data.metricId || r.metricId
|
||||
}
|
||||
}
|
||||
const columns = this.allCols.map(c => {
|
||||
const o = { t: c.$type === 'detail' ? 'd' : 'm', s: !!c.isShift }
|
||||
o.id = String(c.$type === 'detail' ? c.itemId : c.metricId)
|
||||
if (c.color && typeof c.color === 'string') o.c = c.color
|
||||
return o
|
||||
})
|
||||
this.activeReport.colConfig = JSON.stringify({ columns })
|
||||
await updateProdReport({ reportId: rid, colConfig: this.activeReport.colConfig })
|
||||
this.$modal.msgSuccess("列配置已保存"); this.colOpen = false
|
||||
await this.loadGrid()
|
||||
} finally { this.colSaving = false }
|
||||
},
|
||||
|
||||
/* grid */
|
||||
async loadGrid() {
|
||||
const rid = this.activeReport.reportId; this.gridLoading = true
|
||||
try {
|
||||
const dr = await listProdDetail({ reportId: rid, pageNum: 1, pageSize: 9999 })
|
||||
await this.restoreAllCols()
|
||||
this.buildGrid(dr.rows || [])
|
||||
this.recalcAll()
|
||||
} finally { this.gridLoading = false }
|
||||
},
|
||||
async restoreAllCols() {
|
||||
await this.loadItems(); await this.loadAllMetrics(this.activeReport.reportId)
|
||||
const cfg = JSON.parse(this.activeReport.colConfig || 'null')
|
||||
if (!cfg || !cfg.columns || !cfg.columns.length) { this.allCols = []; return }
|
||||
|
||||
const cols = []
|
||||
for (const c of cfg.columns) {
|
||||
if (c.t === 'd') {
|
||||
const id = String(c.id)
|
||||
const item = this.allItems.find(i => String(i.itemId) === id)
|
||||
if (item) cols.push({ $type: 'detail', itemId: item.itemId, itemCode: item.itemCode, itemName: item.itemName, unit: item.unit, isShift: !!c.s, color: c.c || null, queryCondition: item.queryCondition, category: item.category })
|
||||
} else if (c.t === 'm') {
|
||||
const id = String(c.id)
|
||||
let def = (this._allMetricDefs || []).find(m => String(m.metricId) === id)
|
||||
// fallback: try to fetch metric by ID individually if not in cached list
|
||||
if (!def && c.id) {
|
||||
try { const r = await getProdMetric(c.id); if (r.data) { def = r.data; this._allMetricDefs.push(def) } } catch(e) {}
|
||||
}
|
||||
if (def) cols.push({ $type: 'metric', metricId: def.metricId, metricName: def.metricName, metricFormula: def.metricFormula, unit: def.remark||'', isShift: !!c.s, color: c.c || null })
|
||||
}
|
||||
}
|
||||
this.allCols = cols
|
||||
let mi = 0; this.allCols.forEach(c => { if (c.$type === 'metric') c.mIdx = mi++ })
|
||||
},
|
||||
buildGrid(details) {
|
||||
const map = {}; details.forEach(d => {
|
||||
if (!d.detailDate) return
|
||||
if (!map[d.detailDate]) map[d.detailDate] = { detailDate: d.detailDate }
|
||||
const sfx = d.shift && d.shift !== '0' ? '_' + d.shift : ''
|
||||
map[d.detailDate]['q' + d.itemId + sfx] = d.quantity
|
||||
})
|
||||
this.gridRows = Object.values(map).sort((a,b) => a.detailDate.localeCompare(b.detailDate))
|
||||
},
|
||||
recalcAll() {
|
||||
const rp = this.activeReport || {}; const esc = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
const detailCols = this.allCols.filter(c => c.$type === 'detail')
|
||||
const metricCols = this.allCols.filter(c => c.$type === 'metric')
|
||||
this.gridRows.forEach(row => {
|
||||
metricCols.forEach((m, mi) => {
|
||||
if (!m.metricFormula) return
|
||||
const ef = (shiftId) => {
|
||||
let f = m.metricFormula
|
||||
for (let pmi = 0; pmi < mi; pmi++) {
|
||||
const pm = metricCols[pmi]; if (!pm.metricName) continue
|
||||
const pn = esc(pm.metricName)
|
||||
if (pm.isShift) {
|
||||
const pv1 = row['mv'+pm.mIdx+'_1']; const pv2 = row['mv'+pm.mIdx+'_2']
|
||||
if (pv1 != null) f = f.replace(new RegExp('@\\{'+pn+'\\}\\.甲班','g'), pv1)
|
||||
if (pv2 != null) f = f.replace(new RegExp('@\\{'+pn+'\\}\\.乙班','g'), pv2)
|
||||
}
|
||||
const pv = pm.isShift ? (shiftId ? row['mv'+pm.mIdx+'_'+shiftId] : null) : row['mv'+pm.mIdx]
|
||||
if (pv != null) f = f.replace(new RegExp('@\\{'+pn+'\\}','g'), pv)
|
||||
}
|
||||
detailCols.forEach(c => {
|
||||
const item = this.allItems.find(i => String(i.itemId) === String(c.itemId))
|
||||
if (!item || !item.itemCode) return; const code = item.itemCode
|
||||
if (c.isShift) {
|
||||
const v1 = parseFloat(row['q'+c.itemId+'_1'])||0; const v2 = parseFloat(row['q'+c.itemId+'_2'])||0
|
||||
f = f.replace(new RegExp('@\\{'+code+'\\}\\.甲班','g'), v1).replace(new RegExp('@\\{'+code+'\\}\\.乙班','g'), v2)
|
||||
const v = shiftId ? (shiftId==='1'?v1:v2) : v1+v2
|
||||
f = f.replace(new RegExp('@\\{'+code+'\\}','g'), v)
|
||||
} else {
|
||||
const v = parseFloat(row['q'+c.itemId])||0
|
||||
f = f.replace(new RegExp('@\\{'+code+'\\}\\.甲班','g'), v).replace(new RegExp('@\\{'+code+'\\}\\.乙班','g'), v).replace(new RegExp('@\\{'+code+'\\}','g'), v)
|
||||
}
|
||||
})
|
||||
f = f.replace(/input_weight/g, rp.inputWeight||0).replace(/output_weight/g, rp.outputWeight||0)
|
||||
return this.evalF(f)
|
||||
}
|
||||
if (m.isShift) { row['mv'+m.mIdx+'_1']=ef('1'); row['mv'+m.mIdx+'_2']=ef('2') }
|
||||
else row['mv'+m.mIdx]=ef(null)
|
||||
})
|
||||
})
|
||||
},
|
||||
evalF(f) { const s = f.replace(/[^0-9+\-*/.()\s]/g,''); if(!s) return null; try { const r = new Function('return ('+s+')')(); return isFinite(r)?Math.round(r*10000)/10000:null } catch(e){ return null } },
|
||||
sortGrid() { this.gridRows.sort((a,b)=>{if(!a.detailDate)return 1;if(!b.detailDate)return -1;return a.detailDate.localeCompare(b.detailDate)}) },
|
||||
async saveGrid() {
|
||||
const rid = this.activeReport.reportId; if (!rid) return; this.saving = true
|
||||
try {
|
||||
const exist = await listProdDetail({ reportId: rid, pageNum: 1, pageSize: 9999 })
|
||||
const ids = (exist.rows||[]).map(d => d.detailId)
|
||||
const detailCols = this.allCols.filter(c => c.$type === 'detail'); const detailList = []
|
||||
this.gridRows.forEach(row => {
|
||||
if (!row.detailDate) return
|
||||
detailCols.forEach(col => {
|
||||
const push = (shift, sfx) => { const qty = row['q'+col.itemId+sfx]; if (qty != null && qty !== '') detailList.push({ reportId: rid, detailDate: row.detailDate, shift: shift||'0', itemId: col.itemId, quantity: qty }) }
|
||||
if (col.isShift) { push('1','_1'); push('2','_2') } else push(null,'')
|
||||
})
|
||||
})
|
||||
await batchSaveProdDetail({ detailIds: ids, prodDetailList: detailList })
|
||||
this.$modal.msgSuccess("保存成功"); await this.loadGrid()
|
||||
} catch(e) { this.$modal.msgError("保存失败") } finally { this.saving = false }
|
||||
},
|
||||
|
||||
/* copy config */
|
||||
async openCopyCfg() { const r = await listProdReport({ pageNum:1, pageSize:9999 }); this.copyReports = (r.rows||[]).filter(rp=>rp.reportId!==this.activeReport.reportId); this.copySrc=null; this.copyCfgOpen=true },
|
||||
async doCopyCfg() {
|
||||
if (!this.copySrc) return; const sr = await getProdReport(this.copySrc.reportId)
|
||||
const srcCfg = JSON.parse(((sr.data&&sr.data.colConfig)||'null'))
|
||||
if (!srcCfg || (!srcCfg.columns && !srcCfg.itemIds)) { this.$modal.msgWarning('源报表无列配置'); return }
|
||||
await this.loadItems(); await this.loadAllMetrics()
|
||||
const usedIds = new Set(this.allCols.filter(c=>c.$type==='detail').map(c=>String(c.itemId)))
|
||||
const usedMids = new Set(this.allCols.filter(c=>c.$type==='metric'&&c.metricId).map(c=>String(c.metricId)))
|
||||
const cols = srcCfg.columns || []
|
||||
cols.forEach(sc => {
|
||||
if (sc.t === 'd') {
|
||||
const sid = String(sc.id)
|
||||
if (!usedIds.has(sid)) { const item = this.allItems.find(i=>String(i.itemId)===sid); if (item) { this.allCols.push({ $type:'detail', itemId:item.itemId, itemCode:item.itemCode, itemName:item.itemName, unit:item.unit, isShift:!!sc.s, color:sc.c||null, queryCondition:item.queryCondition, category:item.category }); usedIds.add(sid) } }
|
||||
}
|
||||
else if (sc.t === 'm') {
|
||||
const sid = String(sc.id)
|
||||
let def = this._allMetricDefs.find(m=>String(m.metricId)===sid)
|
||||
if (def && !usedMids.has(sid)) { usedMids.add(sid); this.allCols.push({ $type:'metric', metricId:String(def.metricId), metricName:def.metricName, metricFormula:def.metricFormula, unit:def.remark||'', isShift:!!sc.s, color:sc.c||null }) }
|
||||
}
|
||||
})
|
||||
this.copyCfgOpen = false; let mi = 0; this.allCols.forEach(c => { if (c.$type === 'metric') c.mIdx = mi++ })
|
||||
this.$modal.msgSuccess('配置已复用')
|
||||
},
|
||||
|
||||
/* auto fetch */
|
||||
async fetchAutoData(col, row, shift) {
|
||||
if (!col.queryCondition || this.autoLoading[col.itemId]) return
|
||||
const handler = queryHandlers[col.category] || queryHandlers['default']
|
||||
if (!handler) { this.$modal.msgWarning(`类别 "${col.category}" 未注册查询处理器`); return }
|
||||
this.$set(this.autoLoading, col.itemId, true)
|
||||
try {
|
||||
const val = await handler(col.queryCondition, row, col, this.activeReport, shift)
|
||||
if (val != null) {
|
||||
const round3 = n => Math.round(n * 1000) / 1000
|
||||
if (Array.isArray(val)) {
|
||||
this.$set(row, 'q' + col.itemId + '_1', round3(val[0]))
|
||||
this.$set(row, 'q' + col.itemId + '_2', round3(val[1]))
|
||||
} else {
|
||||
const key = 'q' + col.itemId + (shift ? '_' + shift : '')
|
||||
this.$set(row, key, round3(val))
|
||||
}
|
||||
this.recalcAll()
|
||||
}
|
||||
} catch (e) {
|
||||
this.$modal.msgError('自动获取数据失败')
|
||||
} finally {
|
||||
this.$set(this.autoLoading, col.itemId, false)
|
||||
}
|
||||
},
|
||||
|
||||
/* helpers */
|
||||
async loadItems() { if (!this.allItems.length) { const r = await listItem({ pageNum:1, pageSize:999 }); this.allItems = r.rows || [] } },
|
||||
async loadAllMetrics(rid) {
|
||||
const q = { pageNum:1, pageSize:99999 }; if (rid) q.reportId = rid
|
||||
const r = await listProdMetric(q); const map = {}
|
||||
;(r.rows||[]).forEach(m => { if (m.metricName && !map[m.metricId]) map[m.metricId] = m })
|
||||
this._allMetricDefs = Object.values(map)
|
||||
},
|
||||
async enter(row) { const r = await getProdReport(row.reportId); if (r.data) this.activeReport = r.data; else this.activeReport = row; this.loadGrid() }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mb8 { margin-bottom: 8px; }
|
||||
/deep/ .el-table--mini td { padding: 2px 0; }
|
||||
/deep/ .el-table--mini th { padding: 4px 0; font-size: 12px; }
|
||||
/deep/ .el-table--mini .cell { padding: 0 3px; line-height: 1.2; }
|
||||
/deep/ .el-input--mini .el-input__inner { height: 24px; line-height: 24px; padding: 0 5px; }
|
||||
/deep/ .el-date-editor.el-input--mini { width: 124px !important; }
|
||||
/deep/ .el-date-editor.el-input--mini .el-input__inner { padding-left: 5px; padding-right: 18px; }
|
||||
/deep/ .el-date-editor.el-input--mini .el-input__prefix { left: auto; right: 2px; }
|
||||
/deep/ .el-button--mini { padding: 4px 8px; font-size: 12px; }
|
||||
/deep/ .el-button--mini.el-button--text { padding: 0; }
|
||||
.report-tab-bar { display: flex; align-items: center; border-bottom: 1px solid #dcdfe6; margin-bottom: 12px; padding: 0 4px; }
|
||||
.report-tabs { flex: 1; display: flex; overflow-x: auto; margin-bottom: -1px; }
|
||||
.report-tab { display: inline-block; padding: 7px 16px; cursor: pointer; border-bottom: 2px solid transparent; white-space: nowrap; font-size: 13px; color: #606266; transition: all 0.2s; user-select: none; }
|
||||
.report-tab:hover { color: #409eff; }
|
||||
.report-tab.active { color: #409eff; border-bottom-color: #409eff; font-weight: 500; }
|
||||
.empty-hint { text-align: center; padding: 60px 0; color: #999; font-size: 14px; }
|
||||
.entry-header { line-height: 28px; }
|
||||
.entry-title { font-weight: bold; font-size: 15px; }
|
||||
.entry-meta { margin-left: 10px; color: #999; font-size: 12px; }
|
||||
.shift-cell { display: flex; align-items: center; }
|
||||
.shift-tag { font-size: 10px; color: #909399; width: 16px; flex-shrink: 0; }
|
||||
.shift-input { flex: 1; min-width: 0; }
|
||||
.shift-metric { font-size: 12px; line-height: 1.5; }
|
||||
.formula-vars { padding: 4px 6px; margin-bottom: 6px; background: #f5f7fa; border-radius: 3px; border: 1px solid #e4e7ed; line-height: 1.8; }
|
||||
.vars-tag { cursor: pointer; margin: 1px; }
|
||||
.vars-tag:hover { opacity: 0.8; }
|
||||
.var-sys { background: #ecf5ff; border-color: #d9ecff; color: #409eff; }
|
||||
.var-mtr { background: #f0f9eb; border-color: #e1f3d8; color: #67c23a; }
|
||||
.drag-handle { cursor: grab; font-size: 14px; color: #909399; padding: 2px; display: inline-flex; align-items: center; }
|
||||
.drag-handle:active { cursor: grabbing; }
|
||||
.drag-handle:hover { color: #409eff; }
|
||||
</style>
|
||||
356
ruoyi-ui/src/views/cost/detail.vue
Normal file
356
ruoyi-ui/src/views/cost/detail.vue
Normal file
@@ -0,0 +1,356 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="生产月报ID" prop="reportId">
|
||||
<el-input
|
||||
v-model="queryParams.reportId"
|
||||
placeholder="请输入生产月报ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="班次 1=甲班 2=乙班" prop="shift">
|
||||
<el-input
|
||||
v-model="queryParams.shift"
|
||||
placeholder="请输入班次 1=甲班 2=乙班"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="日期" prop="detailDate">
|
||||
<el-date-picker clearable
|
||||
v-model="queryParams.detailDate"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="请选择日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="成本项目ID" prop="itemId">
|
||||
<el-input
|
||||
v-model="queryParams.itemId"
|
||||
placeholder="请输入成本项目ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="消耗用量" prop="quantity">
|
||||
<el-input
|
||||
v-model="queryParams.quantity"
|
||||
placeholder="请输入消耗用量"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="单价" prop="unitPrice">
|
||||
<el-input
|
||||
v-model="queryParams.unitPrice"
|
||||
placeholder="请输入单价"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="总金额" prop="amount">
|
||||
<el-input
|
||||
v-model="queryParams.amount"
|
||||
placeholder="请输入总金额"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="prodDetailList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键ID" align="center" prop="detailId" v-if="true"/>
|
||||
<el-table-column label="生产月报ID" align="center" prop="reportId" />
|
||||
<el-table-column label="班次 1=甲班 2=乙班" align="center" prop="shift" />
|
||||
<el-table-column label="日期" align="center" prop="detailDate" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.detailDate, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成本项目ID" align="center" prop="itemId" />
|
||||
<el-table-column label="消耗用量" align="center" prop="quantity" />
|
||||
<el-table-column label="单价" align="center" prop="unitPrice" />
|
||||
<el-table-column label="总金额" align="center" prop="amount" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改生产成本明细对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="生产月报ID" prop="reportId">
|
||||
<el-input v-model="form.reportId" placeholder="请输入生产月报ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="班次 1=甲班 2=乙班" prop="shift">
|
||||
<el-input v-model="form.shift" placeholder="请输入班次 1=甲班 2=乙班" />
|
||||
</el-form-item>
|
||||
<el-form-item label="日期" prop="detailDate">
|
||||
<el-date-picker clearable
|
||||
v-model="form.detailDate"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="成本项目ID" prop="itemId">
|
||||
<el-input v-model="form.itemId" placeholder="请输入成本项目ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="消耗用量" prop="quantity">
|
||||
<el-input v-model="form.quantity" placeholder="请输入消耗用量" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单价" prop="unitPrice">
|
||||
<el-input v-model="form.unitPrice" placeholder="请输入单价" />
|
||||
</el-form-item>
|
||||
<el-form-item label="总金额" prop="amount">
|
||||
<el-input v-model="form.amount" placeholder="请输入总金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listProdDetail, getProdDetail, delProdDetail, addProdDetail, updateProdDetail } from "@/api/cost/prodDetail";
|
||||
|
||||
export default {
|
||||
name: "ProdDetail",
|
||||
data() {
|
||||
return {
|
||||
// 按钮loading
|
||||
buttonLoading: false,
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 生产成本明细表格数据
|
||||
prodDetailList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
reportId: undefined,
|
||||
shift: undefined,
|
||||
detailDate: undefined,
|
||||
itemId: undefined,
|
||||
quantity: undefined,
|
||||
unitPrice: undefined,
|
||||
amount: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询生产成本明细列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listProdDetail(this.queryParams).then(response => {
|
||||
this.prodDetailList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
detailId: undefined,
|
||||
reportId: undefined,
|
||||
shift: undefined,
|
||||
detailDate: undefined,
|
||||
itemId: undefined,
|
||||
quantity: undefined,
|
||||
unitPrice: undefined,
|
||||
amount: undefined,
|
||||
remark: undefined,
|
||||
delFlag: undefined,
|
||||
createBy: undefined,
|
||||
createTime: undefined,
|
||||
updateBy: undefined,
|
||||
updateTime: undefined
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.detailId)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加生产成本明细";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.loading = true;
|
||||
this.reset();
|
||||
const detailId = row.detailId || this.ids
|
||||
getProdDetail(detailId).then(response => {
|
||||
this.loading = false;
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改生产成本明细";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
if (this.form.detailId != null) {
|
||||
updateProdDetail(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addProdDetail(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const detailIds = row.detailId || this.ids;
|
||||
this.$modal.confirm('是否确认删除生产成本明细编号为"' + detailIds + '"的数据项?').then(() => {
|
||||
this.loading = true;
|
||||
return delProdDetail(detailIds);
|
||||
}).then(() => {
|
||||
this.loading = false;
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('cost/prodDetail/export', {
|
||||
...this.queryParams
|
||||
}, `prodDetail_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
314
ruoyi-ui/src/views/cost/index.vue
Normal file
314
ruoyi-ui/src/views/cost/index.vue
Normal file
@@ -0,0 +1,314 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="报表标题" prop="reportTitle">
|
||||
<el-input
|
||||
v-model="queryParams.reportTitle"
|
||||
placeholder="请输入报表标题"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="报表日期" prop="reportDate">
|
||||
<el-date-picker clearable
|
||||
v-model="queryParams.reportDate"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="请选择报表日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="投入量 单位:吨" prop="inputWeight">
|
||||
<el-input
|
||||
v-model="queryParams.inputWeight"
|
||||
placeholder="请输入投入量 单位:吨"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="产出量 单位:吨" prop="outputWeight">
|
||||
<el-input
|
||||
v-model="queryParams.outputWeight"
|
||||
placeholder="请输入产出量 单位:吨"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="prodReportList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键ID" align="center" prop="reportId" v-if="true"/>
|
||||
<el-table-column label="报表标题" align="center" prop="reportTitle" />
|
||||
<el-table-column label="报表日期" align="center" prop="reportDate" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.reportDate, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="投入量 单位:吨" align="center" prop="inputWeight" />
|
||||
<el-table-column label="产出量 单位:吨" align="center" prop="outputWeight" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改生产月报对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="报表标题" prop="reportTitle">
|
||||
<el-input v-model="form.reportTitle" placeholder="请输入报表标题" />
|
||||
</el-form-item>
|
||||
<el-form-item label="报表日期" prop="reportDate">
|
||||
<el-date-picker clearable
|
||||
v-model="form.reportDate"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择报表日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="投入量 单位:吨" prop="inputWeight">
|
||||
<el-input v-model="form.inputWeight" placeholder="请输入投入量 单位:吨" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产出量 单位:吨" prop="outputWeight">
|
||||
<el-input v-model="form.outputWeight" placeholder="请输入产出量 单位:吨" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listProdReport, getProdReport, delProdReport, addProdReport, updateProdReport } from "@/api/cost/prodReport";
|
||||
|
||||
export default {
|
||||
name: "ProdReport",
|
||||
data() {
|
||||
return {
|
||||
// 按钮loading
|
||||
buttonLoading: false,
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 生产月报表格数据
|
||||
prodReportList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
reportTitle: undefined,
|
||||
reportDate: undefined,
|
||||
inputWeight: undefined,
|
||||
outputWeight: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询生产月报列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listProdReport(this.queryParams).then(response => {
|
||||
this.prodReportList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
reportId: undefined,
|
||||
reportTitle: undefined,
|
||||
reportDate: undefined,
|
||||
inputWeight: undefined,
|
||||
outputWeight: undefined,
|
||||
remark: undefined,
|
||||
delFlag: undefined,
|
||||
createBy: undefined,
|
||||
createTime: undefined,
|
||||
updateBy: undefined,
|
||||
updateTime: undefined
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.reportId)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加生产月报";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.loading = true;
|
||||
this.reset();
|
||||
const reportId = row.reportId || this.ids
|
||||
getProdReport(reportId).then(response => {
|
||||
this.loading = false;
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改生产月报";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
if (this.form.reportId != null) {
|
||||
updateProdReport(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addProdReport(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const reportIds = row.reportId || this.ids;
|
||||
this.$modal.confirm('是否确认删除生产月报编号为"' + reportIds + '"的数据项?').then(() => {
|
||||
this.loading = true;
|
||||
return delProdReport(reportIds);
|
||||
}).then(() => {
|
||||
this.loading = false;
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('cost/prodReport/export', {
|
||||
...this.queryParams
|
||||
}, `prodReport_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
337
ruoyi-ui/src/views/cost/item.vue
Normal file
337
ruoyi-ui/src/views/cost/item.vue
Normal file
@@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="成本项目编码" prop="itemCode">
|
||||
<el-input
|
||||
v-model="queryParams.itemCode"
|
||||
placeholder="请输入成本项目编码"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="成本项目名称" prop="itemName">
|
||||
<el-input
|
||||
v-model="queryParams.itemName"
|
||||
placeholder="请输入成本项目名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="成本分类" prop="category">
|
||||
<el-select
|
||||
v-model="queryParams.category"
|
||||
placeholder="请选择成本分类"
|
||||
clearable
|
||||
@change="handleQuery"
|
||||
>
|
||||
<el-option label="原料" value="原料" />
|
||||
<el-option label="能耗" value="能耗" />
|
||||
<el-option label="辅料" value="辅料" />
|
||||
<el-option label="设备" value="设备" />
|
||||
<el-option label="人工" value="人工" />
|
||||
<el-option label="产出" value="产出" />
|
||||
<el-option label="轧辊" value="轧辊" />
|
||||
<el-option label="其他" value="其他" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="计量单位" prop="unit">
|
||||
<el-input
|
||||
v-model="queryParams.unit"
|
||||
placeholder="请输入计量单位"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="查询条件" prop="queryCondition">
|
||||
<el-input
|
||||
v-model="queryParams.queryCondition"
|
||||
placeholder="请输入查询条件"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="itemList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键ID" align="center" prop="itemId" v-if="true"/>
|
||||
<el-table-column label="成本项目编码" align="center" prop="itemCode" />
|
||||
<el-table-column label="成本项目名称" align="center" prop="itemName" />
|
||||
<el-table-column label="成本分类" align="center" prop="category" />
|
||||
<el-table-column label="计量单位" align="center" prop="unit" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="查询条件" align="center" prop="queryCondition" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改成本项目配置对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="成本项目编码" prop="itemCode">
|
||||
<el-input v-model="form.itemCode" placeholder="请输入成本项目编码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="成本项目名称" prop="itemName">
|
||||
<el-input v-model="form.itemName" placeholder="请输入成本项目名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="成本分类" prop="category">
|
||||
<el-select v-model="form.category" placeholder="请选择成本分类">
|
||||
<el-option label="原料" value="原料" />
|
||||
<el-option label="能耗" value="能耗" />
|
||||
<el-option label="辅料" value="辅料" />
|
||||
<el-option label="设备" value="设备" />
|
||||
<el-option label="人工" value="人工" />
|
||||
<el-option label="产出" value="产出" />
|
||||
<el-option label="轧辊" value="轧辊" />
|
||||
<el-option label="其他" value="其他" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="计量单位" prop="unit">
|
||||
<el-input v-model="form.unit" placeholder="请输入计量单位" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="查询条件" prop="queryCondition">
|
||||
<el-input v-model="form.queryCondition" placeholder="请输入查询条件" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listItem, getItem, delItem, addItem, updateItem } from "@/api/cost/item";
|
||||
|
||||
export default {
|
||||
name: "Item",
|
||||
data() {
|
||||
return {
|
||||
// 按钮loading
|
||||
buttonLoading: false,
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 成本项目配置表格数据
|
||||
itemList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
itemCode: undefined,
|
||||
itemName: undefined,
|
||||
category: undefined,
|
||||
unit: undefined,
|
||||
queryCondition: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询成本项目配置列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listItem(this.queryParams).then(response => {
|
||||
this.itemList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
itemId: undefined,
|
||||
itemCode: undefined,
|
||||
itemName: undefined,
|
||||
category: undefined,
|
||||
unit: undefined,
|
||||
remark: undefined,
|
||||
queryCondition: undefined,
|
||||
delFlag: undefined,
|
||||
createBy: undefined,
|
||||
createTime: undefined,
|
||||
updateBy: undefined,
|
||||
updateTime: undefined
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.itemId)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加成本项目配置";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.loading = true;
|
||||
this.reset();
|
||||
const itemId = row.itemId || this.ids
|
||||
getItem(itemId).then(response => {
|
||||
this.loading = false;
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改成本项目配置";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
if (this.form.itemId != null) {
|
||||
updateItem(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addItem(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const itemIds = row.itemId || this.ids;
|
||||
this.$modal.confirm('是否确认删除成本项目配置编号为"' + itemIds + '"的数据项?').then(() => {
|
||||
this.loading = true;
|
||||
return delItem(itemIds);
|
||||
}).then(() => {
|
||||
this.loading = false;
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('cost/item/export', {
|
||||
...this.queryParams
|
||||
}, `item_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
319
ruoyi-ui/src/views/cost/metric.vue
Normal file
319
ruoyi-ui/src/views/cost/metric.vue
Normal file
@@ -0,0 +1,319 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="生产日报ID" prop="reportId">
|
||||
<el-input
|
||||
v-model="queryParams.reportId"
|
||||
placeholder="请输入生产日报ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="指标编码" prop="metricCode">
|
||||
<el-input
|
||||
v-model="queryParams.metricCode"
|
||||
placeholder="请输入指标编码"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="指标名称" prop="metricName">
|
||||
<el-input
|
||||
v-model="queryParams.metricName"
|
||||
placeholder="请输入指标名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="指标计算公式" prop="metricFormula">
|
||||
<el-input
|
||||
v-model="queryParams.metricFormula"
|
||||
placeholder="请输入指标计算公式"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="指标计算结果值" prop="metricValue">
|
||||
<el-input
|
||||
v-model="queryParams.metricValue"
|
||||
placeholder="请输入指标计算结果值"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="prodMetricList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键ID" align="center" prop="metricId" v-if="true"/>
|
||||
<el-table-column label="生产日报ID" align="center" prop="reportId" />
|
||||
<el-table-column label="指标编码" align="center" prop="metricCode" />
|
||||
<el-table-column label="指标名称" align="center" prop="metricName" />
|
||||
<el-table-column label="指标计算公式" align="center" prop="metricFormula" />
|
||||
<el-table-column label="指标计算结果值" align="center" prop="metricValue" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改生产指标明细对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="生产日报ID" prop="reportId">
|
||||
<el-input v-model="form.reportId" placeholder="请输入生产日报ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="指标编码" prop="metricCode">
|
||||
<el-input v-model="form.metricCode" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
<el-form-item label="指标名称" prop="metricName">
|
||||
<el-input v-model="form.metricName" placeholder="请输入指标名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="指标计算公式" prop="metricFormula">
|
||||
<el-input v-model="form.metricFormula" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
<el-form-item label="指标计算结果值" prop="metricValue">
|
||||
<el-input v-model="form.metricValue" placeholder="请输入指标计算结果值" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listProdMetric, getProdMetric, delProdMetric, addProdMetric, updateProdMetric } from "@/api/cost/prodMetric";
|
||||
|
||||
export default {
|
||||
name: "ProdMetric",
|
||||
data() {
|
||||
return {
|
||||
// 按钮loading
|
||||
buttonLoading: false,
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 生产指标明细表格数据
|
||||
prodMetricList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
reportId: undefined,
|
||||
metricCode: undefined,
|
||||
metricName: undefined,
|
||||
metricFormula: undefined,
|
||||
metricValue: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询生产指标明细列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listProdMetric(this.queryParams).then(response => {
|
||||
this.prodMetricList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
metricId: undefined,
|
||||
reportId: undefined,
|
||||
metricCode: undefined,
|
||||
metricName: undefined,
|
||||
metricFormula: undefined,
|
||||
metricValue: undefined,
|
||||
remark: undefined,
|
||||
delFlag: undefined,
|
||||
createBy: undefined,
|
||||
createTime: undefined,
|
||||
updateBy: undefined,
|
||||
updateTime: undefined
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.metricId)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加生产指标明细";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.loading = true;
|
||||
this.reset();
|
||||
const metricId = row.metricId || this.ids
|
||||
getProdMetric(metricId).then(response => {
|
||||
this.loading = false;
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改生产指标明细";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
if (this.form.metricId != null) {
|
||||
updateProdMetric(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addProdMetric(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const metricIds = row.metricId || this.ids;
|
||||
this.$modal.confirm('是否确认删除生产指标明细编号为"' + metricIds + '"的数据项?').then(() => {
|
||||
this.loading = true;
|
||||
return delProdMetric(metricIds);
|
||||
}).then(() => {
|
||||
this.loading = false;
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('cost/prodMetric/export', {
|
||||
...this.queryParams
|
||||
}, `prodMetric_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
300
ruoyi-ui/src/views/cost/price.vue
Normal file
300
ruoyi-ui/src/views/cost/price.vue
Normal file
@@ -0,0 +1,300 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="成本项目ID" prop="itemId">
|
||||
<el-input
|
||||
v-model="queryParams.itemId"
|
||||
placeholder="请输入成本项目ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="单价" prop="price">
|
||||
<el-input
|
||||
v-model="queryParams.price"
|
||||
placeholder="请输入单价"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="生效日期" prop="effectiveDate">
|
||||
<el-date-picker clearable
|
||||
v-model="queryParams.effectiveDate"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="请选择生效日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="priceList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键ID" align="center" prop="priceId" v-if="true"/>
|
||||
<el-table-column label="成本项目ID" align="center" prop="itemId" />
|
||||
<el-table-column label="单价" align="center" prop="price" />
|
||||
<el-table-column label="生效日期" align="center" prop="effectiveDate" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.effectiveDate, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改成本单价历史对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="成本项目ID" prop="itemId">
|
||||
<el-input v-model="form.itemId" placeholder="请输入成本项目ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单价" prop="price">
|
||||
<el-input v-model="form.price" placeholder="请输入单价" />
|
||||
</el-form-item>
|
||||
<el-form-item label="生效日期" prop="effectiveDate">
|
||||
<el-date-picker clearable
|
||||
v-model="form.effectiveDate"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择生效日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listPrice, getPrice, delPrice, addPrice, updatePrice } from "@/api/cost/price";
|
||||
|
||||
export default {
|
||||
name: "Price",
|
||||
data() {
|
||||
return {
|
||||
// 按钮loading
|
||||
buttonLoading: false,
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 成本单价历史表格数据
|
||||
priceList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
itemId: undefined,
|
||||
price: undefined,
|
||||
effectiveDate: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询成本单价历史列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listPrice(this.queryParams).then(response => {
|
||||
this.priceList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
priceId: undefined,
|
||||
itemId: undefined,
|
||||
price: undefined,
|
||||
effectiveDate: undefined,
|
||||
remark: undefined,
|
||||
delFlag: undefined,
|
||||
createBy: undefined,
|
||||
createTime: undefined,
|
||||
updateBy: undefined,
|
||||
updateTime: undefined
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.priceId)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加成本单价历史";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.loading = true;
|
||||
this.reset();
|
||||
const priceId = row.priceId || this.ids
|
||||
getPrice(priceId).then(response => {
|
||||
this.loading = false;
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改成本单价历史";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
if (this.form.priceId != null) {
|
||||
updatePrice(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addPrice(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const priceIds = row.priceId || this.ids;
|
||||
this.$modal.confirm('是否确认删除成本单价历史编号为"' + priceIds + '"的数据项?').then(() => {
|
||||
this.loading = true;
|
||||
return delPrice(priceIds);
|
||||
}).then(() => {
|
||||
this.loading = false;
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('cost/price/export', {
|
||||
...this.queryParams
|
||||
}, `price_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
185
ruoyi-ui/src/views/mill/abnormal/components/AbnormalForm.vue
Normal file
185
ruoyi-ui/src/views/mill/abnormal/components/AbnormalForm.vue
Normal file
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<el-form ref="form" :model="formData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="钢卷号" prop="currentCoilNo">
|
||||
<el-input v-model="formData.currentCoilNo" placeholder="请输入钢卷号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="缺陷描述" prop="remark">
|
||||
<el-input type="textarea" v-model="formData.remark" placeholder="请输入缺陷描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="上下板面" prop="plateSurface">
|
||||
<muti-select v-model="formData.plateSurface" :options="[
|
||||
{label: '上板面', value: '上'},
|
||||
{label: '下板面', value: '下'}]" type="checkbox">
|
||||
</muti-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="断面位置" prop="position">
|
||||
<muti-select v-model="formData.position" :options="dict.type.coil_abnormal_position" type="checkbox">
|
||||
</muti-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-alert title="异常位置为内圈算起" type="info" :closable="false" show-icon size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="异常区间" required>
|
||||
<div style="display: flex; align-items: center;">
|
||||
<el-form-item prop="startPosition">
|
||||
<el-input v-model="formData.startPosition" type="number" placeholder="请输入开始位置" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="endPosition">
|
||||
<el-input v-model="formData.endPosition" type="number" placeholder="请输入结束位置" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="缺陷代码" prop="defectCode">
|
||||
<el-radio-group v-model="formData.defectCode">
|
||||
<el-radio-button v-for="dict in dict.type.coil_abnormal_code" :key="dict.value" :label="dict.value">{{
|
||||
dict.label }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="程度" prop="degree">
|
||||
<el-radio-group v-model="formData.degree">
|
||||
<el-radio-button v-for="dict in dict.type.coil_abnormal_degree" :key="dict.value" :label="dict.value">{{
|
||||
dict.label }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="产线" prop="productionLine">
|
||||
<el-select v-model="formData.productionLine" placeholder="请选择产线">
|
||||
<el-option v-for="dict in dict.type.sys_lines" :key="dict.value" :label="dict.label"
|
||||
:value="dict.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="主缺陷" prop="mainMark">
|
||||
<!-- 0表示否,1表示是 -->
|
||||
<el-checkbox v-model="formData.mainMark" :true-label="1" :false-label="0">是否为主缺陷</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item label="缺陷图片" v-if="formData.mainMark === 1">
|
||||
<image-upload v-model="formData.attachmentFiles" value-mode="url" :limit="3" />
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ImageUpload from '@/components/ImageUpload'
|
||||
import MutiSelect from '@/components/MutiSelect'
|
||||
|
||||
export default {
|
||||
name: "AbnormalForm",
|
||||
components: {
|
||||
ImageUpload,
|
||||
MutiSelect
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
showCoilSelector: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
dicts: ['coil_abnormal_code', 'coil_abnormal_position', 'coil_abnormal_degree', 'sys_lines'],
|
||||
data() {
|
||||
return {
|
||||
rules: {
|
||||
position: [
|
||||
{ required: true, message: '请选择位置', trigger: 'change' },
|
||||
{ validator: this.validateArray, trigger: 'change' }
|
||||
],
|
||||
// plateSurface: [
|
||||
// { required: true, message: '请选择上下板面', trigger: 'change' },
|
||||
// { validator: this.validateArray, trigger: 'change' }
|
||||
// ],
|
||||
startPosition: [
|
||||
{ required: true, message: '请输入开始位置', trigger: ['blur', 'change'] },
|
||||
{ validator: this.validateStartPosition, trigger: ['blur', 'change'] }
|
||||
],
|
||||
endPosition: [
|
||||
{ required: true, message: '请输入结束位置', trigger: ['blur', 'change'] },
|
||||
{ validator: this.validateEndPosition, trigger: ['blur', 'change'] }
|
||||
],
|
||||
defectCode: [
|
||||
{ required: true, message: '请选择缺陷代码', trigger: 'change' }
|
||||
],
|
||||
degree: [
|
||||
{ required: true, message: '请选择程度', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
formData: {
|
||||
get() {
|
||||
const data = this.value || {};
|
||||
return data;
|
||||
},
|
||||
set(newVal) {
|
||||
// 发送时将数组转为CSV
|
||||
const data = { ...newVal };
|
||||
this.$emit('input', data);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 表单验证 */
|
||||
validate(callback) {
|
||||
if (parseInt(this.formData.startPosition) > parseInt(this.formData.endPosition)) {
|
||||
this.$message.error('开始位置必须小于结束位置');
|
||||
return false;
|
||||
}
|
||||
return this.$refs.form.validate(callback);
|
||||
},
|
||||
/** 重置表单 */
|
||||
resetFields() {
|
||||
this.$refs.form.resetFields();
|
||||
const currentCoilId = this.formData.coilId;
|
||||
this.formData = {
|
||||
abnormalId: undefined,
|
||||
coilId: currentCoilId,
|
||||
position: undefined,
|
||||
plateSurface: undefined,
|
||||
startPosition: undefined,
|
||||
endPosition: undefined,
|
||||
length: undefined,
|
||||
mainMark: 0,
|
||||
productionLine: undefined,
|
||||
defectCode: undefined,
|
||||
degree: undefined,
|
||||
remark: undefined,
|
||||
attachmentFiles: undefined
|
||||
};
|
||||
},
|
||||
/** 计算缺陷长度 */
|
||||
calculateLength() {
|
||||
if (this.formData.startPosition && this.formData.endPosition) {
|
||||
this.formData.length = this.formData.endPosition - this.formData.startPosition;
|
||||
}
|
||||
},
|
||||
/** 校验开始位置 */
|
||||
validateStartPosition(rule, value, callback) {
|
||||
if (value < 0) {
|
||||
callback(new Error('开始位置必须为正数'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
/** 校验结束位置 */
|
||||
validateEndPosition(rule, value, callback) {
|
||||
if (value < 0) {
|
||||
callback(new Error('结束位置必须为正数'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
/** 校验数组 */
|
||||
validateArray(rule, value, callback) {
|
||||
if (!value || value.length === 0) {
|
||||
callback(new Error('请至少选择一个选项'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
106
ruoyi-ui/src/views/mill/abnormal/components/AbnormalTable.vue
Normal file
106
ruoyi-ui/src/views/mill/abnormal/components/AbnormalTable.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<el-table :data="list">
|
||||
<el-table-column label="异常钢卷" align="center" prop="currentCoilNo" v-if="showCoil"></el-table-column>
|
||||
<el-table-column label="缺陷描述" align="center" prop="remark" show-overflow-tooltip />
|
||||
<el-table-column label="上下板面" align="center" prop="plateSurface"></el-table-column>
|
||||
<el-table-column label="缺陷位置" align="center" prop="position">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.coil_abnormal_position" :value="scope.row.position" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="开始位置" align="center" prop="startPosition" />
|
||||
<el-table-column label="结束位置" align="center" prop="endPosition" />
|
||||
<el-table-column label="缺陷长度" align="center" prop="length" />
|
||||
<el-table-column label="缺陷代码" align="center" prop="defectCode">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.coil_abnormal_code" :value="scope.row.defectCode" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主缺陷" prop="mainMark">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.mainMark" type="success">是</el-tag>
|
||||
<el-tag v-else type="danger">否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="缺陷图片" align="center" prop="attachmentFiles" width="120">
|
||||
<template slot-scope="scope">
|
||||
<template v-if="scope.row.attachmentFiles">
|
||||
<div v-for="(url, idx) in scope.row.attachmentFiles.split(',')" :key="idx" style="margin-right: 4px;">
|
||||
<el-image
|
||||
style="width: 30px; height: 30px; vertical-align: middle; border-radius: 2px;"
|
||||
:src="url"
|
||||
:preview-src-list="scope.row.attachmentFiles.split(',')"
|
||||
fit="cover"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="程度" align="center" prop="degree">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.coil_abnormal_degree" :value="scope.row.degree" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建人" align="center" prop="createBy" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" v-if="editable">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
editable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showCoil: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
coilInfo: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
dicts: ['coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree'],
|
||||
methods: {
|
||||
handleDelete(row) {
|
||||
if (this.editable) {
|
||||
this.$emit('delete', row);
|
||||
}
|
||||
},
|
||||
handleUpdate(row) {
|
||||
if (this.editable) {
|
||||
this.$emit('update', row);
|
||||
}
|
||||
},
|
||||
// 计算目标列的异常挂载时机
|
||||
// 如果coilInfo.coilId存在,且与row.coilId相同,
|
||||
// 判断钢卷的createBy和row.createBy是否相同
|
||||
// 判断钢卷的createTime与row的createTime是否在一分钟内
|
||||
// 如果是,返回'生产时'
|
||||
// 如果否,返回'补录'
|
||||
getAbnormalTime(row) {
|
||||
if (this.coilInfo.coilId === row.coilId) {
|
||||
if (this.coilInfo.createBy === row.createBy) {
|
||||
if (Math.abs(new Date(this.coilInfo.createTime) - new Date(row.createTime)) < 60 * 1000) {
|
||||
return '生产时'
|
||||
}
|
||||
}
|
||||
}
|
||||
return '补录'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
438
ruoyi-ui/src/views/mill/abnormal/components/ExceptionManager.vue
Normal file
438
ruoyi-ui/src/views/mill/abnormal/components/ExceptionManager.vue
Normal file
@@ -0,0 +1,438 @@
|
||||
<template>
|
||||
<div class="exception-container" v-loading="abnormalLoading">
|
||||
<div class="exception-section">
|
||||
<div class="section-header">
|
||||
<h4 class="section-title">实绩信息</h4>
|
||||
</div>
|
||||
|
||||
<el-descriptions :column="4" border size="small" v-if="rowData">
|
||||
<el-descriptions-item label="成品卷号">{{ rowData.exitMatId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料卷号">{{ rowData.entryMatId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划号">{{ rowData.planNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品类型">{{ rowData.prodCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="钢种">{{ rowData.steelGrade }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成品厚度">{{ rowData.exitThickness }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成品宽度">{{ rowData.exitWidth }}</el-descriptions-item>
|
||||
<el-descriptions-item label="实际重量">{{ rowData.actualWeight }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班号">{{ rowData.groupNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="组号">{{ rowData.shiftNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料厚度">{{ rowData.entryThick }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料宽度">{{ rowData.entryWidth }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料重量">{{ rowData.entryWeight }}</el-descriptions-item>
|
||||
<el-descriptions-item label="上线时间">{{ parseTime(rowData.onlineTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户">{{ rowData.customer }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="4">{{ rowData.remark }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="exception-section">
|
||||
<div class="section-header">
|
||||
<h4 class="section-title">异常记录</h4>
|
||||
<div>
|
||||
<el-button type="primary" size="mini" @click="handleSave" :loading="buttonLoading">保存</el-button>
|
||||
<el-button type="default" icon="el-icon-refresh" plain size="mini" @click="refreshAbnormalList"
|
||||
:loading="abnormalLoading">
|
||||
刷新
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="abnormalList" style="width: 100%" border stripe>
|
||||
<el-table-column label="序号" type="index" width="50" />
|
||||
<el-table-column label="缺陷描述" prop="remark">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.remark" placeholder="请输入缺陷描述" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="开始位置" prop="startPosition" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-input :controls="false" v-model="scope.row.startPosition" placeholder="请输入开始位置" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束位置" prop="endPosition" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-input :controls="false" v-model="scope.row.endPosition" placeholder="请输入结束位置" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="长度" prop="length" width="100">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.endPosition - scope.row.startPosition }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上下版面" prop="plateSurface" width="180">
|
||||
<template slot-scope="scope">
|
||||
<muti-select v-model="scope.row.plateSurface" :options="[
|
||||
{ label: '上板面', value: '上' },
|
||||
{ label: '下板面', value: '下' }]" type="checkbox">
|
||||
</muti-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="断面位置" prop="position" width="240">
|
||||
<template slot-scope="scope">
|
||||
<muti-select v-model="scope.row.position" :options="dict.type.coil_abnormal_position" type="checkbox">
|
||||
</muti-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="缺陷代码" prop="defectCode">
|
||||
<template slot-scope="scope">
|
||||
<div class="radio-single">
|
||||
<el-radio-group v-model="scope.row.defectCode">
|
||||
<el-radio v-for="dict in dict.type.coil_abnormal_code" :key="dict.value" :label="dict.value" @click.native="handleRadioClick(scope.row.defectCode, dict.value, 'defectCode', scope.row)">
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="程度" prop="degree">
|
||||
<template slot-scope="scope">
|
||||
<div class="radio-single">
|
||||
<el-radio-group v-model="scope.row.degree">
|
||||
<el-radio v-for="dict in dict.type.coil_abnormal_degree" :key="dict.value" :label="dict.value" @click.native="handleRadioClick(scope.row.degree, dict.value, 'degree', scope.row)">
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主缺陷" prop="mainMark" width="60">
|
||||
<template slot-scope="scope">
|
||||
<el-checkbox v-model="scope.row.mainMark" :true-label="1" :false-label="0"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="缺陷图片" prop="attachmentFiles" width="180">
|
||||
<template slot-scope="scope">
|
||||
<image-upload v-if="scope.row.mainMark === 1" v-model="scope.row.attachmentFiles" value-mode="url" :limit="3" :is-show-tip="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="scope.row.abnormalId" type="text" size="mini" @click="handleDelete(scope.row)" style="color: #f56c6c;">
|
||||
删除
|
||||
</el-button>
|
||||
<el-button v-else type="text" size="mini" @click="clearRowData(scope.row)">
|
||||
清空
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addCoilAbnormal, listCoilAbnormal, delCoilAbnormal, updateCoilAbnormal } from '@/api/mill/coilAbnormal'
|
||||
import ImageUpload from '@/components/ImageUpload'
|
||||
import MutiSelect from '@/components/MutiSelect'
|
||||
|
||||
export default {
|
||||
name: 'ExceptionManager',
|
||||
components: {
|
||||
ImageUpload,
|
||||
MutiSelect
|
||||
},
|
||||
dicts: ['coil_abnormal_code', 'coil_abnormal_degree', 'coil_abnormal_position'],
|
||||
props: {
|
||||
currentCoilNo: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
rowData: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
coilId() {
|
||||
return this.currentCoilNo
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
abnormalList: [],
|
||||
abnormalLoading: false,
|
||||
buttonLoading: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
coilId: {
|
||||
handler(newVal) {
|
||||
this.loadAbnormalList()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadAbnormalList() {
|
||||
if (!this.coilId) {
|
||||
// 确保至少10个空行
|
||||
this.abnormalList = this.generateEmptyRows(10)
|
||||
return
|
||||
}
|
||||
this.abnormalLoading = true
|
||||
listCoilAbnormal({
|
||||
currentCoilNo: this.coilId
|
||||
}).then(response => {
|
||||
let rows = response.rows || []
|
||||
// 确保至少10个条目
|
||||
if (rows.length < 10) {
|
||||
const emptyRows = this.generateEmptyRows(10 - rows.length)
|
||||
rows = [...rows, ...emptyRows]
|
||||
}
|
||||
this.abnormalList = rows
|
||||
}).catch(error => {
|
||||
console.error('查询异常记录失败:', error)
|
||||
this.$message.error('查询异常记录失败: ' + (error.message || error))
|
||||
// 失败时也要确保至少10个空行
|
||||
this.abnormalList = this.generateEmptyRows(10)
|
||||
}).finally(() => {
|
||||
this.abnormalLoading = false
|
||||
})
|
||||
},
|
||||
generateEmptyRows(count) {
|
||||
const emptyRows = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
emptyRows.push({
|
||||
coilId: this.coilId,
|
||||
position: '',
|
||||
plateSurface: '',
|
||||
startPosition: 0,
|
||||
endPosition: 0,
|
||||
length: 0,
|
||||
mainMark: 0,
|
||||
productionLine: null,
|
||||
defectCode: null,
|
||||
degree: null,
|
||||
remark: null,
|
||||
attachmentFiles: null
|
||||
})
|
||||
}
|
||||
return emptyRows
|
||||
},
|
||||
handleSave() {
|
||||
// 过滤出非空行
|
||||
const nonEmptyRows = this.abnormalList.filter(row => {
|
||||
return row.startPosition || row.endPosition || row.position || row.plateSurface || row.defectCode || row.degree || row.remark
|
||||
})
|
||||
|
||||
// 批量校验
|
||||
for (let i = 0; i < nonEmptyRows.length; i++) {
|
||||
const row = nonEmptyRows[i]
|
||||
const rowIndex = this.abnormalList.indexOf(row) + 1 // 行号从1开始
|
||||
|
||||
if (!row.startPosition || !row.endPosition) {
|
||||
this.$message.error(`第${rowIndex}行:请填写开始位置和结束位置`)
|
||||
return
|
||||
}
|
||||
if (parseInt(row.startPosition) > parseInt(row.endPosition)) {
|
||||
console.log(row, row.startPosition, row.endPosition)
|
||||
this.$message.error(`第${rowIndex}行:开始位置必须小于结束位置`)
|
||||
return
|
||||
}
|
||||
if (!row.position || row.position.length === 0) {
|
||||
this.$message.error(`第${rowIndex}行:请选择断面位置`)
|
||||
return
|
||||
}
|
||||
// if (!row.plateSurface || row.plateSurface.length === 0) {
|
||||
// this.$message.error(`第${rowIndex}行:请选择上下板面`)
|
||||
// return
|
||||
// }
|
||||
if (!row.defectCode) {
|
||||
this.$message.error(`第${rowIndex}行:请选择缺陷代码`)
|
||||
return
|
||||
}
|
||||
if (!row.degree) {
|
||||
this.$message.error(`第${rowIndex}行:请选择程度`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (nonEmptyRows.length === 0) {
|
||||
this.$message.info('没有需要保存的数据')
|
||||
return
|
||||
}
|
||||
|
||||
this.buttonLoading = true
|
||||
|
||||
// 批量请求
|
||||
const requests = nonEmptyRows.map(row => {
|
||||
const saveData = {
|
||||
...row,
|
||||
coilId: this.coilId
|
||||
}
|
||||
|
||||
if (row.abnormalId) {
|
||||
// 更新操作
|
||||
return updateCoilAbnormal(saveData)
|
||||
} else {
|
||||
// 新增操作
|
||||
return addCoilAbnormal(saveData)
|
||||
}
|
||||
})
|
||||
|
||||
// 执行所有请求
|
||||
Promise.all(requests).then(responses => {
|
||||
this.$message.success('批量保存成功')
|
||||
// 刷新列表
|
||||
this.loadAbnormalList()
|
||||
}).catch(error => {
|
||||
console.error('批量保存失败:', error)
|
||||
this.$message.error('批量保存失败: ' + (error.message || error))
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
if (!row.abnormalId) {
|
||||
// 如果没有 abnormalId,直接从列表中移除
|
||||
const index = this.abnormalList.indexOf(row)
|
||||
if (index > -1) {
|
||||
this.abnormalList.splice(index, 1)
|
||||
// 确保列表始终有10个条目
|
||||
if (this.abnormalList.length < 10) {
|
||||
const emptyRows = this.generateEmptyRows(10 - this.abnormalList.length)
|
||||
this.abnormalList = [...this.abnormalList, ...emptyRows]
|
||||
}
|
||||
this.$message.success('空行已移除')
|
||||
}
|
||||
return
|
||||
}
|
||||
this.$modal.confirm('确认删除异常记录吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.buttonLoading = true
|
||||
delCoilAbnormal(row.abnormalId).then(response => {
|
||||
this.$message.success('异常记录删除成功')
|
||||
this.loadAbnormalList()
|
||||
}).catch(error => {
|
||||
console.error('异常记录删除失败:', error)
|
||||
this.$message.error('异常记录删除失败: ' + (error.message || error))
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
refreshAbnormalList() {
|
||||
this.loadAbnormalList()
|
||||
},
|
||||
handleSingleCheckboxChange(val, value, field, row) {
|
||||
if (val) {
|
||||
// 选中状态,设置值
|
||||
row[field] = value
|
||||
} else {
|
||||
// 取消选中状态,清空值
|
||||
if (row[field] === value) {
|
||||
row[field] = null
|
||||
}
|
||||
}
|
||||
},
|
||||
handleSingleCheckboxClick(value, field, row) {
|
||||
// 实现排他单选:如果点击的是当前选中的值,则取消选中;否则选中新值
|
||||
if (row[field] === value) {
|
||||
row[field] = null
|
||||
} else {
|
||||
row[field] = value
|
||||
}
|
||||
},
|
||||
handleRadioClick(currentValue, value, field, row) {
|
||||
// 实现 radio 的取消选择功能:如果点击的是当前选中的值,则取消选中
|
||||
if (currentValue === value) {
|
||||
// 使用 $nextTick 确保在 radio 组件更新后再清空值
|
||||
this.$nextTick(() => {
|
||||
row[field] = null
|
||||
})
|
||||
}
|
||||
},
|
||||
clearRowData(row) {
|
||||
// 清空一行的所有数据
|
||||
row.remark = null
|
||||
row.startPosition = 0
|
||||
row.endPosition = 0
|
||||
row.position = ''
|
||||
row.plateSurface = ''
|
||||
row.mainMark = 0
|
||||
row.defectCode = null
|
||||
row.degree = null
|
||||
row.attachmentFiles = null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.exception-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.exception-section {
|
||||
background-color: #fafafa;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
border: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.exception-section:first-child {
|
||||
flex: 1;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.exception-section:last-child {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding: 12px 16px;
|
||||
background-color: #fafafa;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
border-radius: 0 0 4px 4px;
|
||||
margin-top: -16px;
|
||||
margin-left: -16px;
|
||||
margin-right: -16px;
|
||||
margin-bottom: -16px;
|
||||
}
|
||||
|
||||
.radio-single {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.radio-single .el-radio {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.radio-single .el-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
0
ruoyi-ui/src/views/mill/abnormal/log.vue
Normal file
0
ruoyi-ui/src/views/mill/abnormal/log.vue
Normal file
372
ruoyi-ui/src/views/mill/abnormal/performance.vue
Normal file
372
ruoyi-ui/src/views/mill/abnormal/performance.vue
Normal file
@@ -0,0 +1,372 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="never">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="成品卷号" prop="exitMatId">
|
||||
<el-input
|
||||
v-model="queryParams.exitMatId"
|
||||
placeholder="请输入成品卷号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="来料卷号" prop="entryMatId">
|
||||
<el-input
|
||||
v-model="queryParams.entryMatId"
|
||||
placeholder="请输入来料卷号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="计划号" prop="planNo">
|
||||
<el-input
|
||||
v-model="queryParams.planNo"
|
||||
placeholder="请输入计划号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="班号" prop="groupNo">
|
||||
<el-input
|
||||
v-model="queryParams.groupNo"
|
||||
placeholder="请输入班号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="组号" prop="shiftNo">
|
||||
<el-input
|
||||
v-model="queryParams.shiftNo"
|
||||
placeholder="请输入组号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['mill:actual:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="actualList" @row-click="handleRowClick" highlight-current-row>
|
||||
<el-table-column label="成品卷号" align="center" prop="exitMatId" />
|
||||
<el-table-column label="来料卷号" align="center" prop="entryMatId" />
|
||||
<el-table-column label="计划号" align="center" prop="planNo" />
|
||||
<el-table-column label="产品类型" align="center" prop="prodCode" />
|
||||
<el-table-column label="班号" align="center" prop="groupNo" />
|
||||
<el-table-column label="组号" align="center" prop="shiftNo" />
|
||||
<el-table-column label="钢种" align="center" prop="steelGrade" />
|
||||
<el-table-column label="成品厚度" align="center" prop="exitThickness" />
|
||||
<el-table-column label="成品宽度" align="center" prop="exitWidth" />
|
||||
<el-table-column label="实际重量" align="center" prop="actualWeight" />
|
||||
<el-table-column label="上线时间" align="center" prop="onlineTime" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.onlineTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="状态" align="center" prop="status" /> -->
|
||||
<el-table-column label="操作" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleExceptionManager(scope.row)">异常管理</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" style="margin-top: 20px;">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="never" v-if="currentRow">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="font-size: 16px; font-weight: bold;">明细信息</span>
|
||||
</div>
|
||||
<el-descriptions :column="4" border>
|
||||
<el-descriptions-item label="成品卷号">{{ currentRow.exitMatId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料卷号">{{ currentRow.entryMatId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="分切数">{{ currentRow.subId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="开始位置">{{ currentRow.startPosition }}</el-descriptions-item>
|
||||
<el-descriptions-item label="结束位置">{{ currentRow.endPosition }}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划id">{{ currentRow.planId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划号">{{ currentRow.planNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品类型">{{ currentRow.prodCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班号">{{ currentRow.groupNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="组号">{{ currentRow.shiftNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">{{ currentRow.status }}</el-descriptions-item>
|
||||
<el-descriptions-item label="钢种">{{ currentRow.steelGrade }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料厚度">{{ currentRow.entryThick }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料宽度">{{ currentRow.entryWidth }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料长度">{{ currentRow.entryLength }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来料重量">{{ currentRow.entryWeight }}</el-descriptions-item>
|
||||
<el-descriptions-item label="上表面镀锌量">{{ currentRow.weightTop }}</el-descriptions-item>
|
||||
<el-descriptions-item label="下表面镀锌量">{{ currentRow.weightBottom }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成品长度">{{ currentRow.exitLength }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成品带涂料重量">{{ currentRow.exitNetWeight }}</el-descriptions-item>
|
||||
<el-descriptions-item label="理论重量">{{ currentRow.theoryWeight }}</el-descriptions-item>
|
||||
<el-descriptions-item label="实际重量">{{ currentRow.actualWeight }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成品外径">{{ currentRow.exitOuterDiameter }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成品厚度">{{ currentRow.exitThickness }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成品宽度">{{ currentRow.exitWidth }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户">{{ currentRow.customer }}</el-descriptions-item>
|
||||
<el-descriptions-item label="上线时间">{{ parseTime(currentRow.onlineTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="开始时间">{{ parseTime(currentRow.startTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="结束时间">{{ parseTime(currentRow.endTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="机组号">{{ currentRow.unitCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="工序号">{{ currentRow.processCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否尾卷">{{ currentRow.lastFlag === 1 ? '是' : '否' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否分卷">{{ currentRow.separateFlag === 1 ? '是' : '否' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划来源">{{ currentRow.planOrigin }}</el-descriptions-item>
|
||||
<el-descriptions-item label="锌层厚度">{{ currentRow.zincCoatingThickness }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入场钢卷号">{{ currentRow.enterCoilNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="4">{{ currentRow.remark }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
<el-card shadow="never" v-else>
|
||||
<div style="text-align: center; padding: 40px; color: #909399;">
|
||||
请点击表格行查看明细信息
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" style="margin-top: 20px;">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="never" v-if="currentRow">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="font-size: 16px; font-weight: bold;">异常记录</span>
|
||||
<div style="float: right;">
|
||||
<el-button type="success" plain icon="el-icon-plus" size="mini" @click="handleAbnormalAdd">添加异常</el-button>
|
||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleAbnormalExport">导出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<AbnormalTable
|
||||
ref="abnormalTable"
|
||||
:list="abnormalList"
|
||||
:editable="true"
|
||||
:showCoil="false"
|
||||
@update="handleAbnormalUpdate"
|
||||
@delete="handleAbnormalDelete"
|
||||
/>
|
||||
</el-card>
|
||||
<el-card shadow="never" v-else>
|
||||
<div style="text-align: center; padding: 40px; color: #909399;">
|
||||
请点击表格行查看异常记录
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-dialog :title="exceptionTitle" :visible.sync="exceptionOpen" width="1200px" append-to-body fullscreen>
|
||||
<ExceptionManager :current-coil-no="exceptionCoilNo" :row-data="exceptionRowData" />
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :title="abnormalTitle" :visible.sync="abnormalOpen" width="700px" append-to-body @closed="handleAbnormalDialogClosed">
|
||||
<AbnormalForm ref="abnormalFormRef" v-model="abnormalFormData" />
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitAbnormalForm">确 定</el-button>
|
||||
<el-button @click="abnormalOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listActual } from "@/api/mill/actual";
|
||||
import { listCoilAbnormal, addCoilAbnormal, updateCoilAbnormal, delCoilAbnormal } from "@/api/mill/coilAbnormal";
|
||||
import AbnormalTable from "./components/AbnormalTable";
|
||||
import AbnormalForm from "./components/AbnormalForm";
|
||||
import ExceptionManager from "./components/ExceptionManager";
|
||||
|
||||
export default {
|
||||
name: "Actual",
|
||||
components: {
|
||||
AbnormalTable,
|
||||
AbnormalForm,
|
||||
ExceptionManager
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
showSearch: true,
|
||||
total: 0,
|
||||
actualList: [],
|
||||
currentRow: null,
|
||||
abnormalList: [],
|
||||
abnormalOpen: false,
|
||||
abnormalTitle: "",
|
||||
abnormalFormData: {},
|
||||
exceptionOpen: false,
|
||||
exceptionTitle: "",
|
||||
exceptionCoilNo: "",
|
||||
exceptionRowData: null,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
exitMatId: null,
|
||||
entryMatId: null,
|
||||
subId: null,
|
||||
startPosition: null,
|
||||
endPosition: null,
|
||||
planId: null,
|
||||
planNo: null,
|
||||
prodCode: null,
|
||||
groupNo: null,
|
||||
shiftNo: null,
|
||||
status: null,
|
||||
steelGrade: null,
|
||||
entryThick: null,
|
||||
entryWidth: null,
|
||||
entryLength: null,
|
||||
entryWeight: null,
|
||||
weightTop: null,
|
||||
weightBottom: null,
|
||||
exitLength: null,
|
||||
exitNetWeight: null,
|
||||
theoryWeight: null,
|
||||
actualWeight: null,
|
||||
exitOuterDiameter: null,
|
||||
exitThickness: null,
|
||||
exitWidth: null,
|
||||
customer: null,
|
||||
onlineTime: null,
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
unitCode: null,
|
||||
processCode: null,
|
||||
planOrigin: null,
|
||||
zincCoatingThickness: null,
|
||||
enterCoilNo: null,
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listActual(this.queryParams).then(response => {
|
||||
this.actualList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
handleRowClick(row) {
|
||||
this.currentRow = row;
|
||||
this.loadAbnormalList();
|
||||
},
|
||||
handleExceptionManager(row) {
|
||||
this.exceptionCoilNo = row.exitMatId;
|
||||
this.exceptionRowData = row;
|
||||
this.exceptionTitle = "异常管理 - " + row.exitMatId;
|
||||
this.exceptionOpen = true;
|
||||
},
|
||||
handleExport() {
|
||||
this.download('mill/actual/export', {
|
||||
...this.queryParams
|
||||
}, `actual_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
loadAbnormalList() {
|
||||
if (!this.currentRow || !this.currentRow.exitMatId) {
|
||||
this.abnormalList = [];
|
||||
return;
|
||||
}
|
||||
listCoilAbnormal({ currentCoilNo: this.currentRow.exitMatId }).then(response => {
|
||||
this.abnormalList = response.rows || [];
|
||||
});
|
||||
},
|
||||
handleAbnormalAdd() {
|
||||
this.abnormalFormData = {
|
||||
currentCoilNo: this.currentRow.exitMatId,
|
||||
position: '',
|
||||
plateSurface: '',
|
||||
startPosition: undefined,
|
||||
endPosition: undefined,
|
||||
mainMark: 0,
|
||||
defectCode: undefined,
|
||||
degree: undefined,
|
||||
remark: undefined,
|
||||
attachmentFiles: undefined
|
||||
};
|
||||
this.abnormalTitle = "添加异常记录";
|
||||
this.abnormalOpen = true;
|
||||
},
|
||||
handleAbnormalUpdate(row) {
|
||||
this.abnormalFormData = { ...row };
|
||||
this.abnormalTitle = "修改异常记录";
|
||||
this.abnormalOpen = true;
|
||||
},
|
||||
submitAbnormalForm() {
|
||||
const formRef = this.$refs.abnormalFormRef;
|
||||
if (!formRef || !formRef.validate) {
|
||||
this.$message.error("表单组件未就绪");
|
||||
return;
|
||||
}
|
||||
formRef.validate(valid => {
|
||||
if (valid) {
|
||||
const data = { ...this.abnormalFormData };
|
||||
if (Array.isArray(data.position)) data.position = data.position.join(",");
|
||||
if (Array.isArray(data.plateSurface)) data.plateSurface = data.plateSurface.join(",");
|
||||
data.currentCoilNo = this.currentRow.exitMatId;
|
||||
const request = data.abnormalId ? updateCoilAbnormal(data) : addCoilAbnormal(data);
|
||||
request.then(() => {
|
||||
this.$modal.msgSuccess(data.abnormalId ? "修改成功" : "新增成功");
|
||||
this.abnormalOpen = false;
|
||||
this.loadAbnormalList();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
handleAbnormalDelete(row) {
|
||||
this.$modal.confirm('是否确认删除该异常记录?').then(() => {
|
||||
return delCoilAbnormal(row.abnormalId);
|
||||
}).then(() => {
|
||||
this.loadAbnormalList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
handleAbnormalExport() {
|
||||
this.download('wms/coilAbnormal/export', {
|
||||
coilId: this.currentRow.exitMatId
|
||||
}, `abnormal_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
handleAbnormalDialogClosed() {
|
||||
if (this.$refs.abnormalFormRef && this.$refs.abnormalFormRef.resetFields) {
|
||||
this.$refs.abnormalFormRef.resetFields();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
22
ruoyi-ui/src/views/mill/roll/rollLineMixin.js
Normal file
22
ruoyi-ui/src/views/mill/roll/rollLineMixin.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 从 URL query.lineId 读取产线 ID,供各轧辊页面共用。
|
||||
* 组件覆盖 onLineResolved() 执行初始化加载。
|
||||
*
|
||||
* 菜单路径示例:/mes/roll/overview?lineId=1
|
||||
*/
|
||||
export default {
|
||||
computed: {
|
||||
lineId() {
|
||||
const v = this.$route.query.lineId
|
||||
return v != null ? Number(v) : null
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.onLineResolved()
|
||||
},
|
||||
|
||||
methods: {
|
||||
onLineResolved() {}
|
||||
}
|
||||
}
|
||||
932
ruoyi-ui/src/views/mill/roll/working/index.vue
Normal file
932
ruoyi-ui/src/views/mill/roll/working/index.vue
Normal file
@@ -0,0 +1,932 @@
|
||||
<template>
|
||||
<div class="app-container working-roll-page">
|
||||
|
||||
<!-- ① 顶部行:作业辊一览(2/3)+ 可用轧辊(1/3) -->
|
||||
<div class="top-row">
|
||||
|
||||
<!-- 作业辊一览 -->
|
||||
<el-card shadow="never" class="roll-table-card top-row__main">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title"><i class="el-icon-s-grid" /> 作业辊一览</span>
|
||||
<span class="header-meta" v-if="current['1#'] && current['1#'].changeTime">
|
||||
1# 末次换辊:{{ current['1#'].changeTime }}
|
||||
</span>
|
||||
<span class="header-meta" v-if="current['2#'] && current['2#'].changeTime">
|
||||
· 2# 末次换辊:{{ current['2#'].changeTime }}
|
||||
</span>
|
||||
<span style="margin-left:auto;display:flex;align-items:center;gap:6px;flex-wrap:wrap">
|
||||
<el-button size="mini" icon="el-icon-refresh-right" @click="handleOpenChange('1#')">1# 换辊</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh-right" @click="handleOpenChange('2#')">2# 换辊</el-button>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button type="success" size="mini" icon="el-icon-plus" @click="handleAddStandby('1#')">1# 添加下批</el-button>
|
||||
<el-button type="danger" size="mini" icon="el-icon-delete" @click="handleClearStandby('1#')"
|
||||
:disabled="!(standbyList['1#'] && standbyList['1#'].length)">1# 清空</el-button>
|
||||
<el-button type="success" size="mini" icon="el-icon-plus" @click="handleAddStandby('2#')">2# 添加下批</el-button>
|
||||
<el-button type="danger" size="mini" icon="el-icon-delete" @click="handleClearStandby('2#')"
|
||||
:disabled="!(standbyList['2#'] && standbyList['2#'].length)">2# 清空</el-button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
ref="mainTable"
|
||||
:data="mergedRows"
|
||||
v-loading="loadingCurrent['1#'] || loadingCurrent['2#'] || loadingStandby['1#'] || loadingStandby['2#']"
|
||||
:row-class-name="rowClass"
|
||||
:span-method="mergeParamCol"
|
||||
border
|
||||
size="small"
|
||||
style="width:100%"
|
||||
>
|
||||
<el-table-column label="参数" width="126" align="left">
|
||||
<template slot-scope="scope">
|
||||
<span :class="['param-label', scope.row.group]">{{ scope.row.label }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="当前在机轧辊" align="center">
|
||||
<el-table-column label="1#" align="center" min-width="88">
|
||||
<template slot-scope="scope">
|
||||
<param-cell :data="scope.row.cur1" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="2#" align="center" min-width="88">
|
||||
<template slot-scope="scope">
|
||||
<param-cell :data="scope.row.cur2" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="下批轧辊" align="center">
|
||||
<el-table-column label="1#" align="center" min-width="88">
|
||||
<template slot-scope="scope">
|
||||
<div
|
||||
:class="['sb-cell',
|
||||
scope.row.sb1 && scope.row.sb1.standbyId ? 'sb-cell--del' :
|
||||
scope.row.rollType ? 'sb-cell--add' : '']"
|
||||
@click="handleSbCellClick(scope.row.sb1, '1#', scope.row.rollType, scope.row.position)"
|
||||
>
|
||||
<param-cell :data="scope.row.sb1" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="2#" align="center" min-width="88">
|
||||
<template slot-scope="scope">
|
||||
<div
|
||||
:class="['sb-cell',
|
||||
scope.row.sb2 && scope.row.sb2.standbyId ? 'sb-cell--del' :
|
||||
scope.row.rollType ? 'sb-cell--add' : '']"
|
||||
@click="handleSbCellClick(scope.row.sb2, '2#', scope.row.rollType, scope.row.position)"
|
||||
>
|
||||
<param-cell :data="scope.row.sb2" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<!-- 右侧:可用辊 + 工作绩效,纵向叠放 -->
|
||||
<div class="top-row__aside aside-col">
|
||||
|
||||
<!-- 可用轧辊(离线) -->
|
||||
<el-card shadow="never" class="roll-table-card aside-panel">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title"><i class="el-icon-files" /> 可用轧辊(离线)</span>
|
||||
<el-button size="mini" icon="el-icon-refresh" style="margin-left:auto" @click="loadOfflineRolls">刷新</el-button>
|
||||
</div>
|
||||
<el-table v-loading="offlineLoading" :data="offlineRolls" size="small" :height="asideHalfH" style="width:100%">
|
||||
<el-table-column label="辊型" align="center" prop="rollType" width="52">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="mini" :type="scope.row.rollType === 'WR' ? 'primary' : 'warning'">{{ scope.row.rollType }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="轧辊编号" align="center" prop="rollNo" min-width="90" show-overflow-tooltip />
|
||||
<el-table-column label="辊径(mm)" align="center" width="76">
|
||||
<template slot-scope="scope">{{ scope.row.currentDia != null ? scope.row.currentDia : scope.row.initialDia }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="粗糙度" align="center" prop="roughness" width="64" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<!-- 工作绩效 -->
|
||||
<el-card shadow="never" class="roll-table-card aside-panel">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title"><i class="el-icon-data-analysis" /> 工作绩效(实时)</span>
|
||||
<el-button size="mini" icon="el-icon-refresh" style="margin-left:auto" @click="loadRollPerformance">刷新</el-button>
|
||||
</div>
|
||||
<el-table v-loading="perfLoading" :data="perfRows" size="small" :height="asideHalfH" border style="width:100%">
|
||||
<el-table-column label="辊位" align="center" prop="label" width="70" />
|
||||
<el-table-column label="1# 机架" align="center" min-width="1">
|
||||
<template slot-scope="scope">
|
||||
<perf-cell :d="scope.row['1#']" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="2# 机架" align="center" min-width="1">
|
||||
<template slot-scope="scope">
|
||||
<perf-cell :d="scope.row['2#']" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ② 换辊历史 -->
|
||||
<el-card shadow="never" class="roll-table-card" style="margin-top:16px">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title"><i class="el-icon-document" /> 换辊历史</span>
|
||||
<el-form :inline="true" size="small" style="margin-left:auto;margin-bottom:0">
|
||||
<el-form-item label="机架" style="margin-bottom:0">
|
||||
<el-select v-model="historyQuery.standNo" placeholder="全部" clearable style="width:100px" @change="loadHistory">
|
||||
<el-option label="1# 机架" value="1#" />
|
||||
<el-option label="2# 机架" value="2#" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" style="margin-bottom:0">
|
||||
<el-select v-model="historyQuery.changeType" placeholder="全部" clearable style="width:110px" @change="loadHistory">
|
||||
<el-option label="计划换辊" value="计划换辊" />
|
||||
<el-option label="紧急换辊" value="紧急换辊" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间起" style="margin-bottom:0">
|
||||
<el-date-picker v-model="historyQuery.changeTime" type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss" placeholder="开始时间"
|
||||
style="width:160px" @change="loadHistory" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<KLPTable v-loading="historyLoading" :data="historyList">
|
||||
<el-table-column label="换辊编号" align="center" prop="changeNo" width="130" />
|
||||
<el-table-column label="机架" align="center" prop="standNo" width="80" />
|
||||
<el-table-column label="换辊时间" align="center" prop="changeTime" width="160" />
|
||||
<el-table-column label="类型" align="center" prop="changeType" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="small" :type="scope.row.changeType === '紧急换辊' ? 'danger' : ''">{{ scope.row.changeType }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作人" align="center" prop="operator" width="80" />
|
||||
<el-table-column label="换辊辊组" align="left" min-width="160">
|
||||
<template slot-scope="scope">
|
||||
<div class="roll-group-cell">
|
||||
<span v-if="scope.row.upperBrNo" class="rg-item"><b>上BR</b> {{ scope.row.upperBrNo }}<em v-if="scope.row.upperBrDia"> φ{{ scope.row.upperBrDia }}</em></span>
|
||||
<span v-if="scope.row.upperWrNo" class="rg-item"><b>上WR</b> {{ scope.row.upperWrNo }}<em v-if="scope.row.upperWrDia"> φ{{ scope.row.upperWrDia }}</em></span>
|
||||
<span v-if="scope.row.lowerWrNo" class="rg-item"><b>下WR</b> {{ scope.row.lowerWrNo }}<em v-if="scope.row.lowerWrDia"> φ{{ scope.row.lowerWrDia }}</em></span>
|
||||
<span v-if="scope.row.lowerBrNo" class="rg-item"><b>下BR</b> {{ scope.row.lowerBrNo }}<em v-if="scope.row.lowerBrDia"> φ{{ scope.row.lowerBrDia }}</em></span>
|
||||
<span v-if="!scope.row.upperBrNo && !scope.row.upperWrNo && !scope.row.lowerWrNo && !scope.row.lowerBrNo" style="color:#c0c4cc">—</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工作长度(m)" align="center" prop="workLength" width="96">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.workLength != null">{{ scope.row.workLength }}</span>
|
||||
<span v-else style="color:#c0c4cc">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="过卷数" align="center" prop="coilCount" width="72">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.coilCount != null">{{ scope.row.coilCount }}</span>
|
||||
<span v-else style="color:#c0c4cc">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="过卷重量" align="center" prop="totalWeight" width="90">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.totalWeight != null">{{ scope.row.totalWeight }}</span>
|
||||
<span v-else style="color:#c0c4cc">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="left" prop="remark" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" width="110" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleEditHistory(scope.row)">补录</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" style="color:#c5221f"
|
||||
@click="handleDeleteHistory(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</KLPTable>
|
||||
<pagination
|
||||
v-show="historyTotal > 0"
|
||||
:total="historyTotal"
|
||||
:page.sync="historyQuery.pageNum"
|
||||
:limit.sync="historyQuery.pageSize"
|
||||
@pagination="loadHistory"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 换辊确认弹窗(纯展示,无需填写) -->
|
||||
<el-dialog :title="changeForm.standNo + ' 机架 — 确认换辊'" :visible.sync="changeOpen" width="420px" append-to-body @close="resetChangeForm">
|
||||
<div class="roll-preview">
|
||||
<div class="roll-preview__title">以下轧辊将被换入</div>
|
||||
<div class="roll-preview__item">
|
||||
<span class="rp-label">上支撑辊</span>
|
||||
<span class="rp-val">{{ changeForm.upperBrNo || '—' }}</span>
|
||||
<span class="rp-dia" v-if="changeForm.upperBrDia">φ{{ changeForm.upperBrDia }} mm</span>
|
||||
</div>
|
||||
<div class="roll-preview__item">
|
||||
<span class="rp-label">上工作辊</span>
|
||||
<span class="rp-val">{{ changeForm.upperWrNo || '—' }}</span>
|
||||
<span class="rp-dia" v-if="changeForm.upperWrDia">φ{{ changeForm.upperWrDia }} mm</span>
|
||||
</div>
|
||||
<div class="roll-preview__item">
|
||||
<span class="rp-label">下工作辊</span>
|
||||
<span class="rp-val">{{ changeForm.lowerWrNo || '—' }}</span>
|
||||
<span class="rp-dia" v-if="changeForm.lowerWrDia">φ{{ changeForm.lowerWrDia }} mm</span>
|
||||
</div>
|
||||
<div class="roll-preview__item">
|
||||
<span class="rp-label">下支撑辊</span>
|
||||
<span class="rp-val">{{ changeForm.lowerBrNo || '—' }}</span>
|
||||
<span class="rp-dia" v-if="changeForm.lowerBrDia">φ{{ changeForm.lowerBrDia }} mm</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="roll-preview__tip">
|
||||
换辊时间和操作人将由系统自动记录
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<el-button type="primary" :loading="changeSubmitting" @click="submitChange">确认换辊</el-button>
|
||||
<el-button @click="changeOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 换辊历史补录/编辑对话框 -->
|
||||
<el-dialog title="换辊记录补录" :visible.sync="historyEditOpen" width="560px" append-to-body @close="historyEditForm = {}">
|
||||
<el-form ref="historyEditForm" :model="historyEditForm" label-width="100px" size="small">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="机架">
|
||||
<el-input :value="historyEditForm.standNo" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="换辊类型">
|
||||
<el-select v-model="historyEditForm.changeType" style="width:100%">
|
||||
<el-option label="计划换辊" value="计划换辊" />
|
||||
<el-option label="紧急换辊" value="紧急换辊" />
|
||||
<el-option label="三级换辊" value="三级换辊" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="换辊时间">
|
||||
<el-date-picker v-model="historyEditForm.changeTime" type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="操作人">
|
||||
<el-input v-model="historyEditForm.operator" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider content-position="left">工作辊</el-divider>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="上工作辊"><el-input v-model="historyEditForm.upperWrNo" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="上工作辊径"><el-input-number v-model="historyEditForm.upperWrDia" :precision="2" :min="0" style="width:100%" /></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="下工作辊"><el-input v-model="historyEditForm.lowerWrNo" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="下工作辊径"><el-input-number v-model="historyEditForm.lowerWrDia" :precision="2" :min="0" style="width:100%" /></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-divider content-position="left">支撑辊</el-divider>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="上支撑辊"><el-input v-model="historyEditForm.upperBrNo" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="上支撑辊径"><el-input-number v-model="historyEditForm.upperBrDia" :precision="2" :min="0" style="width:100%" /></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="下支撑辊"><el-input v-model="historyEditForm.lowerBrNo" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="下支撑辊径"><el-input-number v-model="historyEditForm.lowerBrDia" :precision="2" :min="0" style="width:100%" /></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="historyEditForm.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button type="primary" @click="submitHistoryEdit">保 存</el-button>
|
||||
<el-button @click="historyEditOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加下批轧辊对话框 -->
|
||||
<el-dialog title="添加下批轧辊" :visible.sync="standbyOpen" width="460px" append-to-body @close="resetStandbyForm">
|
||||
<el-form ref="standbyForm" :model="standbyForm" :rules="standbyRules" label-width="100px">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="机架" prop="standNo">
|
||||
<el-select v-model="standbyForm.standNo" style="width:100%" :disabled="standbyFromCell">
|
||||
<el-option label="1# 机架" value="1#" />
|
||||
<el-option label="2# 机架" value="2#" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="辊型" prop="rollType">
|
||||
<el-input
|
||||
v-if="standbyFromCell"
|
||||
:value="standbyForm.rollType === 'WR' ? '工作辊 WR' : '支撑辊 BR'"
|
||||
readonly style="width:100%"
|
||||
/>
|
||||
<el-select v-else v-model="standbyForm.rollType" placeholder="请选择" style="width:100%"
|
||||
@change="handleStandbyRollTypeChange">
|
||||
<el-option label="工作辊 WR" value="WR" />
|
||||
<el-option label="支撑辊 BR" value="BR" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="辊位" prop="position">
|
||||
<el-input
|
||||
v-if="standbyFromCell"
|
||||
:value="standbyForm.position === 'UP' ? '上辊' : '下辊'"
|
||||
readonly style="width:100%"
|
||||
/>
|
||||
<el-select v-else v-model="standbyForm.position" placeholder="请选择" style="width:100%">
|
||||
<el-option label="上辊" value="UP" />
|
||||
<el-option label="下辊" value="DOWN" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="轧辊编号" prop="rollNo">
|
||||
<el-select v-model="standbyForm.rollNo" placeholder="请选择" filterable style="width:100%">
|
||||
<el-option
|
||||
v-for="no in standbyForm.rollType === 'WR' ? wrOptions : brOptions"
|
||||
:key="no" :label="no" :value="no"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="就绪时间">
|
||||
<el-date-picker v-model="standbyForm.readyTime" type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss" placeholder="默认当前时间" style="width:100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="standbyForm.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button type="primary" @click="submitStandby">确 定</el-button>
|
||||
<el-button @click="standbyOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCurrentRolls, listRollChange, addRollChange, updateRollChange, delRollChange, getRollPerformance } from '@/api/mill/rollChange'
|
||||
import { listRollStandby, addRollStandby, delRollStandby, clearRollStandby } from '@/api/mill/rollStandby'
|
||||
import { listRollOptions, listRollInfo } from '@/api/mill/rollInfo'
|
||||
import rollLineMixin from '../rollLineMixin'
|
||||
|
||||
const ParamCell = {
|
||||
name: 'ParamCell',
|
||||
props: { data: { type: Object, default: null } },
|
||||
render(h) {
|
||||
const d = this.data
|
||||
if (!d || d.val == null || d.val === '') return h('span', { class: 'cell-empty' }, '—')
|
||||
return h('span', { class: 'cell-main' }, String(d.val))
|
||||
}
|
||||
}
|
||||
|
||||
/** 绩效单元格:显示辊号 + 三项统计 */
|
||||
const PerfCell = {
|
||||
name: 'PerfCell',
|
||||
props: { d: { type: Object, default: null } },
|
||||
render(h) {
|
||||
const d = this.d
|
||||
if (!d || !d.rollNo) return h('span', { class: 'cell-empty' }, '—')
|
||||
return h('div', { class: 'perf-cell' }, [
|
||||
h('div', { class: 'perf-roll' }, d.rollNo),
|
||||
h('div', { class: 'perf-stat' }, `${d.workLength != null ? d.workLength + 'm' : '—'} · ${d.coilCount != null ? d.coilCount + '卷' : '—'} · ${d.totalWeight != null ? d.totalWeight : '—'}`)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'WorkingRoll',
|
||||
components: { ParamCell, PerfCell },
|
||||
mixins: [rollLineMixin],
|
||||
data() {
|
||||
return {
|
||||
current: { '1#': {}, '2#': {} },
|
||||
loadingCurrent: { '1#': false, '2#': false },
|
||||
|
||||
standbyList: { '1#': [], '2#': [] },
|
||||
loadingStandby: { '1#': false, '2#': false },
|
||||
|
||||
rollInfoMap: {},
|
||||
|
||||
historyLoading: false,
|
||||
historyList: [],
|
||||
historyTotal: 0,
|
||||
historyQuery: { pageNum: 1, pageSize: 15, standNo: undefined, changeType: undefined, changeTime: undefined },
|
||||
|
||||
wrOptions: [],
|
||||
brOptions: [],
|
||||
|
||||
historyEditOpen: false,
|
||||
historyEditForm: {},
|
||||
|
||||
offlineRolls: [],
|
||||
offlineLoading: false,
|
||||
|
||||
perfData: {},
|
||||
perfLoading: false,
|
||||
|
||||
asideHalfH: 200,
|
||||
|
||||
changeOpen: false,
|
||||
changeSubmitting: false,
|
||||
changeForm: this.getDefaultChangeForm(),
|
||||
|
||||
standbyOpen: false,
|
||||
standbyForm: this.getDefaultStandbyForm(),
|
||||
standbyFromCell: false,
|
||||
standbyRules: {
|
||||
standNo: [{ required: true, message: '请选择机架', trigger: 'change' }],
|
||||
rollType: [{ required: true, message: '请选择辊型', trigger: 'change' }],
|
||||
position: [{ required: true, message: '请选择辊位', trigger: 'change' }],
|
||||
rollNo: [{ required: true, message: '请选择轧辊编号', trigger: 'change' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
mergedRows() {
|
||||
const c1 = this.current['1#'] || {}
|
||||
const c2 = this.current['2#'] || {}
|
||||
const ri = this.rollInfoMap
|
||||
|
||||
// 当前辊:值来自换辊记录,凸度/粗糙度/材质从 rollInfoMap 查
|
||||
const cv = (val, rollNo) => ({
|
||||
val: (val == null || val === '') ? null : val,
|
||||
sub: rollNo || null
|
||||
})
|
||||
const rv = (rollNo, field) => {
|
||||
const info = rollNo ? ri[rollNo] : null
|
||||
const val = info ? info[field] : null
|
||||
return { val: (val == null || val === '') ? null : val, sub: rollNo || null }
|
||||
}
|
||||
|
||||
// 下批辊:优先取 standby 记录自身字段,为空则从 rollInfoMap 读(diameter 对应 currentDia)
|
||||
const sv = (standNo, rollType, pos, field) => {
|
||||
const item = (this.standbyList[standNo] || []).find(
|
||||
i => i.rollType === rollType && i.position === pos
|
||||
)
|
||||
if (!item) return { val: null, sub: null }
|
||||
let val = item[field]
|
||||
if ((val == null || val === '') && item.rollNo) {
|
||||
const info = ri[item.rollNo]
|
||||
if (info) {
|
||||
val = field === 'diameter'
|
||||
? (info.currentDia != null ? info.currentDia : info.initialDia)
|
||||
: info[field]
|
||||
}
|
||||
}
|
||||
return { val: (val == null || val === '') ? null : val, sub: item.rollNo, standbyId: item.standbyId }
|
||||
}
|
||||
const sm = (standNo, rollType, pos) => {
|
||||
const item = (this.standbyList[standNo] || []).find(
|
||||
i => i.rollType === rollType && i.position === pos
|
||||
)
|
||||
if (!item || !item.rollNo) return { val: null, sub: null }
|
||||
const info = ri[item.rollNo]
|
||||
return {
|
||||
val: info ? (info.material || null) : null,
|
||||
sub: item.rollNo,
|
||||
standbyId: item.standbyId
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
label: '上支承辊直径(mm)', group: 'br', rollType: 'BR', position: 'UP',
|
||||
cur1: cv(c1.upperBrDia, c1.upperBrNo), cur2: cv(c2.upperBrDia, c2.upperBrNo),
|
||||
sb1: sv('1#', 'BR', 'UP', 'diameter'), sb2: sv('2#', 'BR', 'UP', 'diameter')
|
||||
},
|
||||
{
|
||||
label: '上工作辊直径(mm)', group: 'wr', rollType: 'WR', position: 'UP',
|
||||
cur1: cv(c1.upperWrDia, c1.upperWrNo), cur2: cv(c2.upperWrDia, c2.upperWrNo),
|
||||
sb1: sv('1#', 'WR', 'UP', 'diameter'), sb2: sv('2#', 'WR', 'UP', 'diameter')
|
||||
},
|
||||
{
|
||||
label: '上工作辊凸度', group: 'wr', rollType: 'WR', position: 'UP',
|
||||
cur1: rv(c1.upperWrNo, 'crown'), cur2: rv(c2.upperWrNo, 'crown'),
|
||||
sb1: sv('1#', 'WR', 'UP', 'crown'), sb2: sv('2#', 'WR', 'UP', 'crown')
|
||||
},
|
||||
{
|
||||
label: '上工作辊粗糙度(μm)', group: 'wr', rollType: 'WR', position: 'UP',
|
||||
cur1: rv(c1.upperWrNo, 'roughness'), cur2: rv(c2.upperWrNo, 'roughness'),
|
||||
sb1: sv('1#', 'WR', 'UP', 'roughness'), sb2: sv('2#', 'WR', 'UP', 'roughness')
|
||||
},
|
||||
{
|
||||
label: '工作辊类型', group: 'wr', rollType: 'WR', position: 'UP',
|
||||
cur1: rv(c1.upperWrNo, 'material'), cur2: rv(c2.upperWrNo, 'material'),
|
||||
sb1: sm('1#', 'WR', 'UP'), sb2: sm('2#', 'WR', 'UP')
|
||||
},
|
||||
{
|
||||
label: '下工作辊直径(mm)', group: 'wr', rollType: 'WR', position: 'DOWN',
|
||||
cur1: cv(c1.lowerWrDia, c1.lowerWrNo), cur2: cv(c2.lowerWrDia, c2.lowerWrNo),
|
||||
sb1: sv('1#', 'WR', 'DOWN', 'diameter'), sb2: sv('2#', 'WR', 'DOWN', 'diameter')
|
||||
},
|
||||
{
|
||||
label: '下工作辊凸度', group: 'wr', rollType: 'WR', position: 'DOWN',
|
||||
cur1: rv(c1.lowerWrNo, 'crown'), cur2: rv(c2.lowerWrNo, 'crown'),
|
||||
sb1: sv('1#', 'WR', 'DOWN', 'crown'), sb2: sv('2#', 'WR', 'DOWN', 'crown')
|
||||
},
|
||||
{
|
||||
label: '下工作辊粗糙度(μm)', group: 'wr', rollType: 'WR', position: 'DOWN',
|
||||
cur1: rv(c1.lowerWrNo, 'roughness'), cur2: rv(c2.lowerWrNo, 'roughness'),
|
||||
sb1: sv('1#', 'WR', 'DOWN', 'roughness'), sb2: sv('2#', 'WR', 'DOWN', 'roughness')
|
||||
},
|
||||
{
|
||||
label: '下支承辊直径(mm)', group: 'br', rollType: 'BR', position: 'DOWN',
|
||||
cur1: cv(c1.lowerBrDia, c1.lowerBrNo), cur2: cv(c2.lowerBrDia, c2.lowerBrNo),
|
||||
sb1: sv('1#', 'BR', 'DOWN', 'diameter'), sb2: sv('2#', 'BR', 'DOWN', 'diameter')
|
||||
},
|
||||
{
|
||||
label: '轧线设定(mm)', group: 'pl', rollType: null, position: null,
|
||||
cur1: { val: null, sub: null }, cur2: { val: null, sub: null },
|
||||
sb1: { val: null, sub: null }, sb2: { val: null, sub: null }
|
||||
},
|
||||
{
|
||||
label: '轧线位置(mm)', group: 'pl', rollType: null, position: null,
|
||||
cur1: { val: null, sub: null }, cur2: { val: null, sub: null },
|
||||
sb1: { val: null, sub: null }, sb2: { val: null, sub: null }
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
/** 工作绩效表数据行:4 辊位 × {label, 1#, 2#} */
|
||||
perfRows() {
|
||||
const POS = [
|
||||
{ key: 'upperBr', label: '上支撑辊' },
|
||||
{ key: 'upperWr', label: '上工作辊' },
|
||||
{ key: 'lowerWr', label: '下工作辊' },
|
||||
{ key: 'lowerBr', label: '下支撑辊' }
|
||||
]
|
||||
return POS.map(p => ({
|
||||
label: p.label,
|
||||
'1#': (this.perfData[p.key] || {})['1#'] || {},
|
||||
'2#': (this.perfData[p.key] || {})['2#'] || {}
|
||||
}))
|
||||
}
|
||||
},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {
|
||||
this.$nextTick(this.syncAsideHeight)
|
||||
window.addEventListener('resize', this.syncAsideHeight)
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.syncAsideHeight)
|
||||
},
|
||||
|
||||
methods: {
|
||||
onLineResolved() {
|
||||
this.loadAll()
|
||||
this.loadRollOptions()
|
||||
this.loadRollInfoMap()
|
||||
},
|
||||
|
||||
getDefaultChangeForm(standNo) {
|
||||
return {
|
||||
standNo: standNo || undefined,
|
||||
changeType: undefined,
|
||||
changeTime: undefined,
|
||||
operator: undefined,
|
||||
upperWrNo: undefined,
|
||||
upperWrDia: undefined,
|
||||
lowerWrNo: undefined,
|
||||
lowerWrDia: undefined,
|
||||
upperBrNo: undefined,
|
||||
upperBrDia: undefined,
|
||||
lowerBrNo: undefined,
|
||||
lowerBrDia: undefined,
|
||||
remark: undefined
|
||||
}
|
||||
},
|
||||
getDefaultStandbyForm(standNo, rollType, position) {
|
||||
return {
|
||||
standNo: standNo || undefined,
|
||||
rollType: rollType || undefined,
|
||||
position: position || undefined,
|
||||
rollNo: undefined,
|
||||
readyTime: undefined,
|
||||
remark: undefined
|
||||
}
|
||||
},
|
||||
loadAll() {
|
||||
;['1#', '2#'].forEach(s => {
|
||||
this.loadCurrent(s)
|
||||
this.loadStandby(s)
|
||||
})
|
||||
this.loadHistory()
|
||||
this.loadOfflineRolls()
|
||||
this.loadRollPerformance()
|
||||
},
|
||||
|
||||
loadRollPerformance() {
|
||||
this.perfLoading = true
|
||||
getRollPerformance(this.lineId).then(res => {
|
||||
this.perfData = res.data || {}
|
||||
}).finally(() => { this.perfLoading = false })
|
||||
},
|
||||
|
||||
loadCurrent(standNo) {
|
||||
this.$set(this.loadingCurrent, standNo, true)
|
||||
getCurrentRolls(this.lineId, standNo).then(res => {
|
||||
this.$set(this.current, standNo, res.data || {})
|
||||
this.$set(this.loadingCurrent, standNo, false)
|
||||
this.$nextTick(this.syncAsideHeight)
|
||||
}).catch(() => { this.$set(this.loadingCurrent, standNo, false) })
|
||||
},
|
||||
|
||||
loadStandby(standNo) {
|
||||
this.$set(this.loadingStandby, standNo, true)
|
||||
listRollStandby(this.lineId, standNo).then(res => {
|
||||
this.$set(this.standbyList, standNo, res.data || [])
|
||||
this.$set(this.loadingStandby, standNo, false)
|
||||
}).catch(() => { this.$set(this.loadingStandby, standNo, false) })
|
||||
},
|
||||
|
||||
loadHistory() {
|
||||
this.historyLoading = true
|
||||
listRollChange({ ...this.historyQuery, lineId: this.lineId }).then(res => {
|
||||
this.historyList = res.rows || []
|
||||
this.historyTotal = res.total || 0
|
||||
this.historyLoading = false
|
||||
}).catch(() => { this.historyLoading = false })
|
||||
},
|
||||
|
||||
loadRollOptions() {
|
||||
// 下批辊选择只显示离线(Offline)状态的轧辊,限定当前产线
|
||||
listRollOptions(this.lineId, 'WR', 'Offline').then(res => { this.wrOptions = res.data || [] })
|
||||
listRollOptions(this.lineId, 'BR', 'Offline').then(res => { this.brOptions = res.data || [] })
|
||||
},
|
||||
|
||||
loadRollInfoMap() {
|
||||
listRollInfo({ lineId: this.lineId, pageNum: 1, pageSize: 500 }).then(res => {
|
||||
const map = {}
|
||||
;(res.rows || []).forEach(r => { map[r.rollNo] = r })
|
||||
this.rollInfoMap = map
|
||||
})
|
||||
},
|
||||
|
||||
rowClass({ row }) {
|
||||
if (row.group === 'br') return 'row-br'
|
||||
if (row.group === 'pl') return 'row-pl'
|
||||
return ''
|
||||
},
|
||||
|
||||
// el-table span-method:参数列不需要 span,其余无特殊合并
|
||||
mergeParamCol({ columnIndex }) {
|
||||
if (columnIndex === 0) return [1, 1]
|
||||
},
|
||||
|
||||
// 换辊:自动从下批辊填入辊号和径值
|
||||
handleOpenChange(standNo) {
|
||||
const list = this.standbyList[standNo] || []
|
||||
const ri = this.rollInfoMap
|
||||
|
||||
const pick = (rollType, pos) => {
|
||||
const item = list.find(i => i.rollType === rollType && i.position === pos)
|
||||
if (!item) return { no: undefined, dia: undefined }
|
||||
const info = ri[item.rollNo]
|
||||
const dia = item.diameter != null ? item.diameter
|
||||
: (info ? (info.currentDia != null ? info.currentDia : info.initialDia) : undefined)
|
||||
return { no: item.rollNo, dia }
|
||||
}
|
||||
|
||||
const uwr = pick('WR', 'UP')
|
||||
const lwr = pick('WR', 'DOWN')
|
||||
const ubr = pick('BR', 'UP')
|
||||
const lbr = pick('BR', 'DOWN')
|
||||
|
||||
this.changeForm = {
|
||||
...this.getDefaultChangeForm(standNo),
|
||||
lineId: this.lineId,
|
||||
upperWrNo: uwr.no, upperWrDia: uwr.dia,
|
||||
lowerWrNo: lwr.no, lowerWrDia: lwr.dia,
|
||||
upperBrNo: ubr.no, upperBrDia: ubr.dia,
|
||||
lowerBrNo: lbr.no, lowerBrDia: lbr.dia
|
||||
}
|
||||
this.changeOpen = true
|
||||
},
|
||||
submitChange() {
|
||||
if (this.changeSubmitting) return
|
||||
this.changeSubmitting = true
|
||||
const standNo = this.changeForm.standNo
|
||||
addRollChange(this.changeForm).then(() => {
|
||||
this.$modal.msgSuccess('换辊成功')
|
||||
this.changeOpen = false
|
||||
clearRollStandby(this.lineId, standNo).finally(() => {
|
||||
this.loadCurrent(standNo)
|
||||
this.loadStandby(standNo)
|
||||
this.loadHistory()
|
||||
this.loadOfflineRolls()
|
||||
this.loadRollPerformance()
|
||||
})
|
||||
}).finally(() => {
|
||||
this.changeSubmitting = false
|
||||
})
|
||||
},
|
||||
resetChangeForm() {
|
||||
this.changeForm = this.getDefaultChangeForm()
|
||||
this.changeSubmitting = false
|
||||
},
|
||||
|
||||
// 下批轧辊 — 单元格点击(空→新增,有数据→删除)
|
||||
handleSbCellClick(cell, standNo, rollType, position) {
|
||||
if (cell && cell.standbyId) {
|
||||
this.handleDelStandby(cell.standbyId, standNo)
|
||||
} else if (rollType) {
|
||||
this.standbyForm = this.getDefaultStandbyForm(standNo, rollType, position)
|
||||
this.standbyFromCell = true
|
||||
this.standbyOpen = true
|
||||
}
|
||||
},
|
||||
|
||||
// 下批轧辊 — 顶部"添加下批"按钮(不预设辊型辊位)
|
||||
handleAddStandby(standNo) {
|
||||
this.standbyForm = this.getDefaultStandbyForm(standNo)
|
||||
this.standbyFromCell = false
|
||||
this.standbyOpen = true
|
||||
},
|
||||
handleStandbyRollTypeChange() {
|
||||
this.$set(this.standbyForm, 'rollNo', undefined)
|
||||
},
|
||||
submitStandby() {
|
||||
this.$refs.standbyForm.validate(valid => {
|
||||
if (!valid) return
|
||||
addRollStandby({ ...this.standbyForm, lineId: this.lineId }).then(() => {
|
||||
this.$modal.msgSuccess('已添加到下批轧辊')
|
||||
this.standbyOpen = false
|
||||
this.loadStandby(this.standbyForm.standNo)
|
||||
this.loadRollOptions() // 刷新离线辊下拉(已变为 Standby 的辊不再显示)
|
||||
this.loadOfflineRolls() // 刷新可用辊面板
|
||||
})
|
||||
})
|
||||
},
|
||||
resetStandbyForm() {
|
||||
this.standbyForm = this.getDefaultStandbyForm()
|
||||
this.standbyFromCell = false
|
||||
this.$nextTick(() => { this.$refs.standbyForm && this.$refs.standbyForm.clearValidate() })
|
||||
},
|
||||
handleDelStandby(standbyId, standNo) {
|
||||
this.$modal.confirm('确认移除该下批轧辊?移除后该辊状态将恢复为"离线"。').then(() => {
|
||||
return delRollStandby(standbyId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('已移除')
|
||||
this.loadStandby(standNo)
|
||||
this.loadRollOptions()
|
||||
this.loadOfflineRolls()
|
||||
})
|
||||
},
|
||||
handleClearStandby(standNo) {
|
||||
this.$modal.confirm('确认清空 ' + standNo + ' 机架的全部下批轧辊?').then(() => {
|
||||
return clearRollStandby(this.lineId, standNo)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('已清空')
|
||||
this.loadStandby(standNo)
|
||||
})
|
||||
},
|
||||
|
||||
// ── 换辊历史 补录 / 删除 ──────────────────────────────────
|
||||
handleEditHistory(row) {
|
||||
this.historyEditForm = { ...row }
|
||||
this.historyEditOpen = true
|
||||
},
|
||||
submitHistoryEdit() {
|
||||
updateRollChange(this.historyEditForm).then(() => {
|
||||
this.$modal.msgSuccess('保存成功')
|
||||
this.historyEditOpen = false
|
||||
this.loadHistory()
|
||||
})
|
||||
},
|
||||
handleDeleteHistory(row) {
|
||||
this.$modal.confirm('确认删除该换辊记录?此操作不可恢复。').then(() => {
|
||||
return delRollChange(row.changeId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('已删除')
|
||||
this.loadHistory()
|
||||
})
|
||||
},
|
||||
|
||||
// ── 可用离线辊列表 ────────────────────────────────────────
|
||||
loadOfflineRolls() {
|
||||
this.offlineLoading = true
|
||||
listRollInfo({ lineId: this.lineId, status: 'Offline', pageNum: 1, pageSize: 30 }).then(res => {
|
||||
this.offlineRolls = res.rows || []
|
||||
}).finally(() => {
|
||||
this.offlineLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 右侧两个面板各占左侧表格高度的一半(各自减去卡片头高度)
|
||||
syncAsideHeight() {
|
||||
const el = this.$refs.mainTable && this.$refs.mainTable.$el
|
||||
if (!el) return
|
||||
const totalH = el.offsetHeight // 左侧 el-table 实际高度
|
||||
const gap = 12 // 两个面板之间的间距
|
||||
const headerH = 48 // 单个卡片 header 高度估值
|
||||
const half = Math.max(100, Math.floor((totalH - gap) / 2) - headerH)
|
||||
this.asideHalfH = half
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.working-roll-page { background: #f4f5f7; }
|
||||
.roll-table-card { border: 1px solid #dcdee0; border-radius: 4px; }
|
||||
|
||||
/* 顶部两栏布局 */
|
||||
.top-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
}
|
||||
.top-row__main { flex: 2; min-width: 0; }
|
||||
.top-row__aside { flex: 1; min-width: 0; }
|
||||
|
||||
/* 右侧列:两个面板纵向叠放 */
|
||||
.aside-col { display: flex; flex-direction: column; gap: 12px; }
|
||||
.aside-panel { flex: 1; min-width: 0; }
|
||||
|
||||
/* 绩效单元格 */
|
||||
.perf-cell { padding: 2px 0; line-height: 1.4; }
|
||||
.perf-roll { font-family: 'Consolas', monospace; font-size: 12px; font-weight: 600; color: #1f2329; }
|
||||
.perf-stat { font-size: 11px; color: #8f9099; }
|
||||
|
||||
/* 历史换辊辊组 */
|
||||
.roll-group-cell { display: flex; flex-wrap: wrap; gap: 4px; line-height: 1.5; }
|
||||
.rg-item { font-size: 12px; color: #3d4b5c; }
|
||||
.rg-item b { color: #5f6368; font-weight: 600; margin-right: 2px; }
|
||||
.rg-item em { font-style: normal; color: #9aa0a6; font-size: 11px; }
|
||||
|
||||
.card-header { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
||||
.card-title { font-size: 13px; font-weight: 600; color: #3d4b5c; white-space: nowrap; }
|
||||
.header-meta { font-size: 11px; color: #8f9099; white-space: nowrap; }
|
||||
|
||||
/* 参数列文字 */
|
||||
.param-label { font-size: 12px; color: #3d4b5c; }
|
||||
|
||||
/* 数值单元格 */
|
||||
.cell-main { font-family: 'Consolas', 'Courier New', monospace; font-size: 13px; font-weight: 600; color: #1f2329; }
|
||||
.cell-empty { color: #c0c4cc; font-size: 12px; }
|
||||
|
||||
/* 换辊预览卡片 */
|
||||
.roll-preview { background: #f7f8fa; border: 1px solid #e4e6eb; border-radius: 4px; padding: 10px 12px; }
|
||||
.roll-preview__title { font-size: 11px; color: #8f9099; margin-bottom: 8px; letter-spacing: .5px; }
|
||||
.roll-preview__item { display: flex; align-items: center; gap: 6px; padding: 4px 0; }
|
||||
.rp-label { font-size: 12px; color: #8f9099; width: 56px; flex-shrink: 0; }
|
||||
.rp-val { font-size: 13px; font-weight: 600; color: #1f2329; font-family: 'Consolas', monospace; flex: 1; }
|
||||
.rp-dia { font-size: 11px; color: #9aa0a6; }
|
||||
.roll-preview__tip { font-size: 11px; color: #b0b3bb; margin-top: 10px; text-align: center; }
|
||||
|
||||
/* 下批辊单元格容器:填满整个 td,有数据时点击删除 */
|
||||
.sb-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 36px;
|
||||
}
|
||||
/* 有数据 → 点击删除,hover 浅红 */
|
||||
.sb-cell--del {
|
||||
cursor: pointer;
|
||||
}
|
||||
.sb-cell--del:hover {
|
||||
background: rgba(198, 40, 40, 0.07);
|
||||
}
|
||||
/* 空格子 → 点击新增,hover 浅绿 */
|
||||
.sb-cell--add {
|
||||
cursor: pointer;
|
||||
}
|
||||
.sb-cell--add:hover {
|
||||
background: rgba(35, 134, 54, 0.07);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* 行分组色(scoped 无法穿透 el-table 内部) */
|
||||
.working-roll-page .el-table .row-br > td { background-color: #f7f7f6 !important; }
|
||||
.working-roll-page .el-table .row-pl > td { background-color: #eef2f8 !important; }
|
||||
|
||||
/* 列分组标题加粗区分 */
|
||||
.working-roll-page .el-table__header th.el-table__cell {
|
||||
background: #f0f2f5;
|
||||
color: #3d4b5c;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user