完善工艺流程功能迁移
Some checks failed
Release pipeline / publish (push) Has been cancelled
Release pipeline / Always run job (push) Has been cancelled

This commit is contained in:
sheng
2026-06-25 00:46:42 +08:00
parent 46e4c2643b
commit 22ccc9c219
9 changed files with 277 additions and 21 deletions

View File

@@ -1,5 +1,5 @@
<template>
<el-dialog :title="$t(title)" :visible.sync="visible" append-to-body :close-on-click-modal="false" width="70%" :before-close="handleClose">
<el-dialog :title="title" :visible.sync="visible" append-to-body :close-on-click-modal="false" width="70%" :before-close="handleClose">
<div class="toolbar">
<el-button type="primary" size="mini" icon="el-icon-plus" @click="openAdd">
{{ $t(key('add_calculation_script')) }}

View File

@@ -1,6 +1,6 @@
<template>
<el-dialog
:title="$t(title)"
:title="title"
:visible.sync="visible"
append-to-body
:close-on-click-modal="false"

View File

@@ -0,0 +1,197 @@
<template>
<el-dialog
:title="title"
:visible.sync="visible"
:width="width"
append-to-body
:close-on-click-modal="false"
:before-close="handleClose"
>
<wait-plugin
v-if="type === 'WaitPlugin'"
ref="plugin"
:setting-json="pluginData"
@submit="handleChildSubmit"
/>
<json-plugin
v-else
ref="plugin"
:setting-json="pluginData"
:plugin-type="type"
:workingsubclass-code="code"
@submit="handleChildSubmit"
/>
<div slot="footer">
<el-button size="small" @click="handleClose">{{ $t(key('cancel')) }}</el-button>
<el-button type="primary" size="small" @click="handleFormSubmit">{{ $t(key('confirm')) }}</el-button>
</div>
</el-dialog>
</template>
<script>
import { i18nMixin } from '@/composables/useI18n'
function parseSettingJson (value) {
if (value === undefined || value === null || value === '') return { process: {} }
if (typeof value === 'object') return value
try {
return JSON.parse(value)
} catch (e) {
return { process: {} }
}
}
const WaitPlugin = {
name: 'ProcessRoutingWaitPlugin',
mixins: [i18nMixin('page.production_master_data.process_model.process_routing.card')],
props: {
settingJson: { default: '' }
},
data () {
return {
form: { time: undefined, time_range: undefined, alert: '0' },
rules: {
time: [{ pattern: /^[0-9]\d*$/, message: this.key('integer_ge_0'), trigger: 'change' }],
time_range: [{ pattern: /^[0-9]\d*$/, message: this.key('integer_ge_0'), trigger: 'change' }]
}
}
},
watch: {
settingJson: {
handler (val) {
const json = parseSettingJson(val)
this.form = {
time: json.process && json.process.time !== undefined ? json.process.time : undefined,
time_range: json.process && json.process.time_range !== undefined ? json.process.time_range : undefined,
alert: json.process && json.process.alert !== undefined ? json.process.alert : '0'
}
},
immediate: true
}
},
methods: {
handleFormSubmit () {
this.$refs.form.validate(valid => {
if (!valid) {
this.$message.error(this.$t(this.key('validation_fail')))
return
}
this.$emit('submit', { process: { ...this.form } })
})
}
},
template: `
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="mini">
<el-form-item :label="$t(key('rest_time'))" prop="time">
<el-input v-model="form.time" :placeholder="$t(key('enter_rest_time'))" clearable>
<template slot="append">{{ $t(key('minute')) }}</template>
</el-input>
</el-form-item>
<el-form-item :label="$t(key('precision_range'))" prop="time_range">
<el-input v-model="form.time_range" :placeholder="$t(key('enter_precision_range'))" clearable>
<template slot="append">{{ $t(key('minute')) }}</template>
</el-input>
</el-form-item>
</el-form>
`
}
const JsonPlugin = {
name: 'ProcessRoutingJsonPlugin',
mixins: [i18nMixin('page.production_master_data.process_model.process_routing.card')],
props: {
settingJson: { default: '' },
pluginType: { type: String, default: '' },
workingsubclassCode: { type: String, default: '' }
},
data () {
return {
activeTab: 'process',
jsonText: '{}',
parsedJson: { process: {} }
}
},
watch: {
settingJson: {
handler (val) {
this.parsedJson = parseSettingJson(val)
this.jsonText = JSON.stringify(this.parsedJson.process || {}, null, 2)
},
immediate: true
}
},
methods: {
handleFormSubmit () {
if (!this.jsonText) {
this.$message.error(this.$t(this.key('input_empty')))
return
}
try {
this.$emit('submit', { ...this.parsedJson, process: JSON.parse(this.jsonText) })
} catch (e) {
this.$message.error(this.$t(this.key('json_format_error')))
}
}
},
template: `
<el-tabs v-model="activeTab" type="card">
<el-tab-pane :label="$t(key('setting'))" name="process">
<el-alert
v-if="pluginType"
:title="pluginType + (workingsubclassCode ? ' / ' + workingsubclassCode : '')"
type="info"
:closable="false"
show-icon
style="margin-bottom:12px"
/>
<el-input
v-model="jsonText"
type="textarea"
:rows="15"
:placeholder="$t(key('enter_setting_json'))"
/>
</el-tab-pane>
<el-tab-pane label="JSON" name="json">
<pre class="json-preview">{{ JSON.stringify(parsedJson, null, 2) }}</pre>
</el-tab-pane>
</el-tabs>
`
}
export default {
name: 'ProcessRoutingTechnologyFlowModel',
components: { WaitPlugin, JsonPlugin },
mixins: [i18nMixin('page.production_master_data.process_model.process_routing.card')],
props: {
type: { type: String, default: '' },
code: { type: String, default: '' },
title: { type: String, default: '' },
width: { type: String, default: '35%' },
visible: { type: Boolean, default: false },
pluginData: { default: '' }
},
methods: {
handleClose () {
this.$emit('close')
},
handleFormSubmit () {
this.$refs.plugin && this.$refs.plugin.handleFormSubmit()
},
handleChildSubmit (data) {
this.$emit('submit', data)
}
}
}
</script>
<style scoped>
.json-preview {
max-height: 360px;
overflow: auto;
padding: 12px;
background: #f5f7fa;
border: 1px solid #dcdfe6;
border-radius: 4px;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<el-drawer :visible.sync="visible" :wrapper-closable="false" :with-header="false" size="50%">
<div class="drawer-title">
<el-page-header @back="handleClose" :content="$t(title)" />
<el-page-header @back="handleClose" :content="title" />
</div>
<div class="section">

View File

@@ -191,7 +191,7 @@ import {
import { getWorkingsubclassAll } from '@/api/production-master-data/process-step'
import PageTable from '@/components/page-table'
import PageDialogForm from '@/components/page-dialog-form'
import TechnologyFlowModel from '../process-step/components/technology-flow-model.vue'
import TechnologyFlowModel from './components/technology-flow-model.vue'
import ResultParam from './components/result-param.vue'
import TemperatureCompensation from './components/temperature-compensation.vue'
import CalculationScript from './components/calculation-script.vue'
@@ -295,8 +295,8 @@ export default {
{
type: 'select',
prop: 'pin_check',
label: this.$t(this.key('pin_check')),
placeholder: this.$t(this.key('select_pin_check')),
label: this.key('pin_check'),
placeholder: this.key('select_pin_check'),
clearable: false,
style: { width: '90%' },
options: [
@@ -314,6 +314,7 @@ export default {
this.columns = useTableColumns([
{ prop: 'up', label: '', slot: 'up', width: 40 },
{ prop: 'down', label: '', slot: 'down', width: 40 },
{ prop: 'sort', label: this.key('sort'), slot: 'sort', width: 80 },
{ prop: 'code', label: this.key('step_code'), minWidth: 120 },
{ prop: 'name', label: this.key('step_name'), minWidth: 140 },
{ prop: 'workingsubclass_name', label: this.key('process_unit_name'), minWidth: 140 },
@@ -398,6 +399,25 @@ export default {
}
},
methods: {
normalizeResponse (res) {
const getTotal = (source, fallback) => {
if (!source) return fallback
const total = source.count ?? source.total ?? source.total_count ?? source.record_count
const value = Number(total)
return Number.isNaN(value) ? fallback : value
}
const containers = [res, res && res.data, res && res.data && res.data.data].filter(Boolean)
for (const item of containers) {
if (Array.isArray(item)) {
return { list: item, total: getTotal(res, item.length) }
}
const list = item.data || item.list || item.rows || item.records || item.items
if (Array.isArray(list)) {
return { list, total: getTotal(item, getTotal(res, list.length)) }
}
}
return { list: [], total: 0 }
},
async fetchData () {
this.loading = true
try {
@@ -465,7 +485,7 @@ export default {
loadWorkingsubclassOptions () {
if (this.workingsubclassOptions.length > 0) return Promise.resolve()
return getWorkingsubclassAll().then(res => {
const list = res.data || res || []
const list = this.normalizeResponse(res).list
this.workingsubclassRawData = list
this.workingsubclassOptions = list.map(item => ({
label: item.name,
@@ -573,25 +593,26 @@ export default {
},
openSettingDrawer (row) {
this.settingRowId = row.id
this.settingTitle = this.key('setting')
this.settingType = row.setting_plugin || row.device_category_code || ''
this.settingTitle = `${row.name}${this.$t(this.key('setting'))}`
this.settingType = row.setting_plugin || ''
this.settingCode = row.workingsubclass_code || row.code || ''
this.settingWidth = row.setting_plugin_width ? `${row.setting_plugin_width}%` : '35%'
this.settingPluginData = row.setting || {}
this.settingVisible = true
},
openResultParamDrawer (row) {
this.resultTitle = this.key('result_param')
this.resultTitle = `${row.name}${this.$t(this.key('result_param'))}`
this.resultWorkingsubclassId = row.workingsubclass_id || ''
this.resultFlowProcessId = row.id || ''
this.resultVisible = true
},
openTemperatureDrawer (row) {
this.temperatureTitle = this.key('temperature')
this.temperatureTitle = `${row.name}${this.$t(this.key('temperature'))}`
this.temperatureFlowProcessId = row.id || ''
this.temperatureVisible = true
},
openCalculationScriptDrawer (row) {
this.calculationTitle = this.key('calculation_script')
this.calculationTitle = `${row.name}${this.$t(this.key('calculation_script'))}`
this.calculationFlowProcessId = row.id || ''
this.calculationVisible = true
},

View File

@@ -287,6 +287,25 @@ export default {
this.fetchData()
},
methods: {
normalizeResponse (res) {
const getTotal = (source, fallback) => {
if (!source) return fallback
const total = source.count ?? source.total ?? source.total_count ?? source.record_count
const value = Number(total)
return Number.isNaN(value) ? fallback : value
}
const containers = [res, res && res.data, res && res.data && res.data.data].filter(Boolean)
for (const item of containers) {
if (Array.isArray(item)) {
return { list: item, total: getTotal(res, item.length) }
}
const list = item.data || item.list || item.rows || item.records || item.items
if (Array.isArray(list)) {
return { list, total: getTotal(item, getTotal(res, list.length)) }
}
}
return { list: [], total: 0 }
},
async fetchData () {
this.loading = true
try {
@@ -295,10 +314,9 @@ export default {
page_no: this.pagination.current,
page_size: this.pagination.size
})
const list = Array.isArray(res) ? res : (res.data || [])
const total = Array.isArray(res) ? res.length : (res.count || 0)
this.tableData = list
this.pagination.total = total
const data = this.normalizeResponse(res)
this.tableData = data.list
this.pagination.total = data.total
} finally {
this.loading = false
}
@@ -336,7 +354,7 @@ export default {
loadDialogCategories () {
if (this.categoryOptions.length > 0) return
getProcessCategoryAll().then(res => {
this.categoryOptions = (res.data || res || []).map(item => ({
this.categoryOptions = this.normalizeResponse(res).list.map(item => ({
label: item.name,
value: item.id
}))
@@ -346,7 +364,7 @@ export default {
loadDialogProducts () {
if (this.productOptions.length > 0) return
getProductBatteryAll().then(res => {
this.productOptions = (res.data || res || []).map(item => ({
this.productOptions = this.normalizeResponse(res).list.map(item => ({
label: item.name,
value: item.product_model_id
}))
@@ -356,13 +374,13 @@ export default {
loadSearchCategories () {
if (this.searchCategoryOptions.length > 0) return
getProcessCategoryAll().then(res => {
this.searchCategoryOptions = res.data || res || []
this.searchCategoryOptions = this.normalizeResponse(res).list
})
},
loadSearchProducts () {
if (this.searchProductOptions.length > 0) return
getProductBatteryAll().then(res => {
this.searchProductOptions = res.data || res || []
this.searchProductOptions = this.normalizeResponse(res).list
})
},
openAdd () {