Files
mes-ui-d2/src/views/production-master-data/process-model/process-routing-card/components/temperature-compensation.vue

210 lines
8.2 KiB
Vue
Raw Normal View History

<template>
<el-drawer :visible.sync="visible" :wrapper-closable="false" :with-header="false" size="50%">
<div class="drawer-title">
2026-06-25 00:46:42 +08:00
<el-page-header @back="handleClose" :content="title" />
</div>
<div class="section">
<div class="section-title">| {{ $t(key('temperature_step_range')) }}</div>
<el-form :inline="true" :model="formTemp" size="mini">
<el-form-item :label="$t(key('start_step'))">
<el-select v-model="formTemp.start_work_step_id" :placeholder="$t(key('select_start_step'))" @change="checkStepRange">
<el-option v-for="item in stepOptions" :key="item.id" :label="item.suffix_name || item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="$t(key('end_step'))">
<el-select v-model="formTemp.end_work_step_id" :placeholder="$t(key('select_end_step'))" @change="checkStepRange">
<el-option v-for="item in stepOptions" :key="item.id" :label="item.suffix_name || item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-form>
</div>
<div class="section">
<div class="section-title">| {{ $t(key('temperature_data')) }}</div>
<div class="toolbar">
<el-button size="mini" icon="el-icon-plus" @click="addRow">{{ $t(key('add')) }}</el-button>
<el-button size="mini" icon="el-icon-delete" @click="removeRows">{{ $t(key('remove')) }}</el-button>
<el-button size="mini" type="primary" icon="el-icon-check" @click="saveRows">{{ $t(key('save')) }}</el-button>
<el-button size="mini" icon="el-icon-upload2" @click="importVisible = true">{{ $t(key('import_data')) }}</el-button>
</div>
<el-table ref="table" :data="tableData" border height="560" @selection-change="selectedRows = $event">
<el-table-column type="selection" width="48" />
<el-table-column :label="$t(key('temperature_value'))" min-width="160">
<template slot-scope="{ row }">
<el-input v-model="row.temperature" size="mini" />
</template>
</el-table-column>
<el-table-column :label="$t(key('compensation_value'))" min-width="160">
<template slot-scope="{ row }">
<el-input v-model="row.compensation_value" size="mini" />
</template>
</el-table-column>
</el-table>
</div>
<el-dialog :title="$t(key('import_temperature_data'))" :visible.sync="importVisible" append-to-body width="420px">
<el-upload
drag
action=""
:auto-upload="false"
:show-file-list="false"
accept=".xls,.xlsx"
:on-change="onFileChange"
>
<i class="el-icon-upload" />
<div class="el-upload__text">{{ $t(key('drag_file_here')) }}<em>{{ $t(key('click_to_upload')) }}</em></div>
<div slot="tip" class="el-upload__tip">{{ fileName }}</div>
</el-upload>
<span slot="footer">
<el-button type="primary" :loading="templateLoading" @click="downloadTemplate">{{ $t(key('download_template')) }}</el-button>
</span>
</el-dialog>
</el-drawer>
</template>
<script>
import { i18nMixin } from '@/composables/useI18n'
import { getStep, getTemperatureList, createTemperature, getTemperatureTemplate } from '@/api/production-master-data/process-routing-card'
import { downloadRename, readExcel } from '@/utils/file'
export default {
name: 'ProcessRoutingCardTemperatureCompensation',
mixins: [i18nMixin('page.production_master_data.process_model.process_routing.card')],
props: {
title: { type: String, default: '' },
visible: { type: Boolean, default: false },
flowProcessId: { type: [String, Number], default: '' }
},
data () {
return {
formTemp: { start_work_step_id: '', end_work_step_id: '' },
stepOptions: [],
tableData: [],
selectedRows: [],
importVisible: false,
fileName: '',
templateLoading: false
}
},
watch: {
visible (val) {
if (val) this.bootstrap()
}
},
methods: {
handleClose () {
this.$emit('close')
},
async bootstrap () {
await Promise.all([this.loadSteps(), this.loadTemperatureList()])
},
async loadSteps () {
const res = await getStep({})
this.stepOptions = (res && res.data) || res || []
},
async loadTemperatureList () {
if (!this.flowProcessId) return
const res = await getTemperatureList({ process_id: this.flowProcessId })
const data = (res && res.data) || res || {}
this.tableData = data.data || []
this.formTemp.start_work_step_id = data.start_work_step_id || ''
this.formTemp.end_work_step_id = data.end_work_step_id || ''
},
checkStepRange () {
const start = Number(this.formTemp.start_work_step_id)
const end = Number(this.formTemp.end_work_step_id)
if (start && end && start > end) this.$message.warning(this.$t(this.key('start_step_greater_than_end')))
},
addRow () {
this.tableData.push({ temperature: '', compensation_value: '' })
},
removeRows () {
if (!this.selectedRows.length) {
this.$message.error(this.$t(this.key('select_at_least_one')))
return
}
this.tableData = this.tableData.filter(row => !this.selectedRows.includes(row))
},
validateRows () {
if (!this.formTemp.start_work_step_id) return this.$t(this.key('select_start_step_required'))
if (!this.formTemp.end_work_step_id) return this.$t(this.key('select_end_step_required'))
const seen = {}
for (const row of this.tableData) {
if (row.temperature === '' || row.temperature === null || row.temperature === undefined) return this.$t(this.key('temperature_required'))
if (row.compensation_value === '' || row.compensation_value === null || row.compensation_value === undefined) return this.$t(this.key('compensation_required'))
if (!/^[-]?\d+(\.\d+)?$/.test(String(row.temperature))) return this.$t(this.key('temperature_must_be_numeric'))
if (!/^[-]?\d+(\.\d+)?$/.test(String(row.compensation_value))) return this.$t(this.key('compensation_must_be_numeric'))
if (seen[row.temperature]) return this.$t(this.key('duplicate_temperature_exists'))
seen[row.temperature] = true
}
return ''
},
async saveRows () {
const error = this.validateRows()
if (error) {
this.$message.error(error)
return
}
await createTemperature({
temp_data: this.tableData,
start_work_step_id: this.formTemp.start_work_step_id,
end_work_step_id: this.formTemp.end_work_step_id,
process_id: this.flowProcessId
})
this.$message.success(this.$t(this.key('operation_success')))
this.loadTemperatureList()
},
async downloadTemplate () {
this.templateLoading = true
try {
const res = await getTemperatureTemplate({})
downloadRename(res, 'xlsx', this.$t(this.key('temperature_template_name')))
} finally {
this.templateLoading = false
}
},
async onFileChange (file) {
if (!file || !/\.(xls|xlsx)$/i.test(file.name)) {
this.$message.error(this.$t(this.key('invalid_upload_format')))
return
}
this.fileName = file.name
const rows = await readExcel(file.raw)
const next = [...this.tableData]
for (const row of rows) {
if (!Object.prototype.hasOwnProperty.call(row, '温度') || !Object.prototype.hasOwnProperty.call(row, '温度补偿值')) {
this.$message.error(this.$t(this.key('temperature_import_columns_required')))
return
}
if (next.some(item => String(item.temperature) === String(row['温度']))) {
this.$message.error(this.$t(this.key('duplicate_temperature_exists')))
return
}
next.push({ temperature: row['温度'], compensation_value: row['温度补偿值'] })
}
this.tableData = next.sort((a, b) => Number(a.temperature) - Number(b.temperature))
this.importVisible = false
}
}
}
</script>
<style scoped>
.drawer-title {
padding: 20px 0 20px 20px;
border-bottom: 1px solid #dcdfe6;
}
.section {
margin: 20px;
}
.section-title {
margin-bottom: 16px;
color: #409EFF;
font-size: 14px;
}
.toolbar {
margin-bottom: 10px;
}
</style>