feat: 新增产品标准、工艺路线及工序参数管理功能
本次提交新增了以下内容: 1. 为产品标准BO的生效日期和失效日期添加Json格式化注解 2. 新增工艺主表、工序参数明细的前后端CRUD接口与页面 3. 新增产品标准相关的全套CRUD接口 4. 新增产品标准管理页面,包含产品用途、化学成分等多类子功能模块
This commit is contained in:
@@ -68,11 +68,13 @@ public class PtProductStandardBo extends BaseEntity {
|
||||
/**
|
||||
* 生效日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date effectiveDate;
|
||||
|
||||
/**
|
||||
* 失效日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date expireDate;
|
||||
|
||||
/**
|
||||
|
||||
35
klp-ui/src/api/pt/process.js
Normal file
35
klp-ui/src/api/pt/process.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// ==================== 工艺主表 ====================
|
||||
export function listProcesse(query) {
|
||||
return request({ url: '/pt/processe/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProcesse(processId) {
|
||||
return request({ url: '/pt/processe/' + processId, method: 'get' })
|
||||
}
|
||||
export function addProcesse(data) {
|
||||
return request({ url: '/pt/processe', method: 'post', data })
|
||||
}
|
||||
export function updateProcesse(data) {
|
||||
return request({ url: '/pt/processe', method: 'put', data })
|
||||
}
|
||||
export function delProcesse(processIds) {
|
||||
return request({ url: '/pt/processe/' + processIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 工序参数明细 ====================
|
||||
export function listProcessStepParam(query) {
|
||||
return request({ url: '/pt/processStepParam/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProcessStepParam(paramId) {
|
||||
return request({ url: '/pt/processStepParam/' + paramId, method: 'get' })
|
||||
}
|
||||
export function addProcessStepParam(data) {
|
||||
return request({ url: '/pt/processStepParam', method: 'post', data })
|
||||
}
|
||||
export function updateProcessStepParam(data) {
|
||||
return request({ url: '/pt/processStepParam', method: 'put', data })
|
||||
}
|
||||
export function delProcessStepParam(paramIds) {
|
||||
return request({ url: '/pt/processStepParam/' + paramIds, method: 'delete' })
|
||||
}
|
||||
154
klp-ui/src/api/pt/standard.js
Normal file
154
klp-ui/src/api/pt/standard.js
Normal file
@@ -0,0 +1,154 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// ==================== 产品标准主表 ====================
|
||||
export function listProductStandard(query) {
|
||||
return request({ url: '/pt/productStandard/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductStandard(standardId) {
|
||||
return request({ url: '/pt/productStandard/' + standardId, method: 'get' })
|
||||
}
|
||||
export function addProductStandard(data) {
|
||||
return request({ url: '/pt/productStandard', method: 'post', data })
|
||||
}
|
||||
export function updateProductStandard(data) {
|
||||
return request({ url: '/pt/productStandard', method: 'put', data })
|
||||
}
|
||||
export function delProductStandard(standardIds) {
|
||||
return request({ url: '/pt/productStandard/' + standardIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 产品用途 ====================
|
||||
export function listProductApplication(query) {
|
||||
return request({ url: '/pt/productApplication/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductApplication(applicationId) {
|
||||
return request({ url: '/pt/productApplication/' + applicationId, method: 'get' })
|
||||
}
|
||||
export function addProductApplication(data) {
|
||||
return request({ url: '/pt/productApplication', method: 'post', data })
|
||||
}
|
||||
export function updateProductApplication(data) {
|
||||
return request({ url: '/pt/productApplication', method: 'put', data })
|
||||
}
|
||||
export function delProductApplication(applicationIds) {
|
||||
return request({ url: '/pt/productApplication/' + applicationIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 化学成分 ====================
|
||||
export function listProductChemicalComposition(query) {
|
||||
return request({ url: '/pt/productChemicalComposition/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductChemicalComposition(compositionId) {
|
||||
return request({ url: '/pt/productChemicalComposition/' + compositionId, method: 'get' })
|
||||
}
|
||||
export function addProductChemicalComposition(data) {
|
||||
return request({ url: '/pt/productChemicalComposition', method: 'post', data })
|
||||
}
|
||||
export function updateProductChemicalComposition(data) {
|
||||
return request({ url: '/pt/productChemicalComposition', method: 'put', data })
|
||||
}
|
||||
export function delProductChemicalComposition(compositionIds) {
|
||||
return request({ url: '/pt/productChemicalComposition/' + compositionIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 镀层规格 ====================
|
||||
export function listProductCoatingSpec(query) {
|
||||
return request({ url: '/pt/productCoatingSpec/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductCoatingSpec(coatingId) {
|
||||
return request({ url: '/pt/productCoatingSpec/' + coatingId, method: 'get' })
|
||||
}
|
||||
export function addProductCoatingSpec(data) {
|
||||
return request({ url: '/pt/productCoatingSpec', method: 'post', data })
|
||||
}
|
||||
export function updateProductCoatingSpec(data) {
|
||||
return request({ url: '/pt/productCoatingSpec', method: 'put', data })
|
||||
}
|
||||
export function delProductCoatingSpec(coatingIds) {
|
||||
return request({ url: '/pt/productCoatingSpec/' + coatingIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 尺寸规格 ====================
|
||||
export function listProductDimension(query) {
|
||||
return request({ url: '/pt/productDimension/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductDimension(dimensionId) {
|
||||
return request({ url: '/pt/productDimension/' + dimensionId, method: 'get' })
|
||||
}
|
||||
export function addProductDimension(data) {
|
||||
return request({ url: '/pt/productDimension', method: 'post', data })
|
||||
}
|
||||
export function updateProductDimension(data) {
|
||||
return request({ url: '/pt/productDimension', method: 'put', data })
|
||||
}
|
||||
export function delProductDimension(dimensionIds) {
|
||||
return request({ url: '/pt/productDimension/' + dimensionIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 物理性能 ====================
|
||||
export function listProductPhysicalProperty(query) {
|
||||
return request({ url: '/pt/productPhysicalProperty/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductPhysicalProperty(propertyId) {
|
||||
return request({ url: '/pt/productPhysicalProperty/' + propertyId, method: 'get' })
|
||||
}
|
||||
export function addProductPhysicalProperty(data) {
|
||||
return request({ url: '/pt/productPhysicalProperty', method: 'post', data })
|
||||
}
|
||||
export function updateProductPhysicalProperty(data) {
|
||||
return request({ url: '/pt/productPhysicalProperty', method: 'put', data })
|
||||
}
|
||||
export function delProductPhysicalProperty(propertyIds) {
|
||||
return request({ url: '/pt/productPhysicalProperty/' + propertyIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 参考标准 ====================
|
||||
export function listProductRefStandard(query) {
|
||||
return request({ url: '/pt/productRefStandard/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductRefStandard(refId) {
|
||||
return request({ url: '/pt/productRefStandard/' + refId, method: 'get' })
|
||||
}
|
||||
export function addProductRefStandard(data) {
|
||||
return request({ url: '/pt/productRefStandard', method: 'post', data })
|
||||
}
|
||||
export function updateProductRefStandard(data) {
|
||||
return request({ url: '/pt/productRefStandard', method: 'put', data })
|
||||
}
|
||||
export function delProductRefStandard(refIds) {
|
||||
return request({ url: '/pt/productRefStandard/' + refIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 尺寸公差 ====================
|
||||
export function listProductTolerance(query) {
|
||||
return request({ url: '/klp/productTolerance/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductTolerance(toleranceId) {
|
||||
return request({ url: '/klp/productTolerance/' + toleranceId, method: 'get' })
|
||||
}
|
||||
export function addProductTolerance(data) {
|
||||
return request({ url: '/klp/productTolerance', method: 'post', data })
|
||||
}
|
||||
export function updateProductTolerance(data) {
|
||||
return request({ url: '/klp/productTolerance', method: 'put', data })
|
||||
}
|
||||
export function delProductTolerance(toleranceIds) {
|
||||
return request({ url: '/klp/productTolerance/' + toleranceIds, method: 'delete' })
|
||||
}
|
||||
|
||||
// ==================== 表面质量 ====================
|
||||
export function listProductSurfaceSpec(query) {
|
||||
return request({ url: '/pt/productSurfaceSpec/list', method: 'get', params: query })
|
||||
}
|
||||
export function getProductSurfaceSpec(surfaceId) {
|
||||
return request({ url: '/pt/productSurfaceSpec/' + surfaceId, method: 'get' })
|
||||
}
|
||||
export function addProductSurfaceSpec(data) {
|
||||
return request({ url: '/pt/productSurfaceSpec', method: 'post', data })
|
||||
}
|
||||
export function updateProductSurfaceSpec(data) {
|
||||
return request({ url: '/pt/productSurfaceSpec', method: 'put', data })
|
||||
}
|
||||
export function delProductSurfaceSpec(surfaceIds) {
|
||||
return request({ url: '/pt/productSurfaceSpec/' + surfaceIds, method: 'delete' })
|
||||
}
|
||||
675
klp-ui/src/views/pt/processe/index.vue
Normal file
675
klp-ui/src/views/pt/processe/index.vue
Normal file
@@ -0,0 +1,675 @@
|
||||
<template>
|
||||
<div class="pt-process-page">
|
||||
<DragResizePanel :initialSize="300" :minSize="240" :maxSize="550">
|
||||
<!-- ==================== 左侧面板:工艺列表 ==================== -->
|
||||
<template #panelA>
|
||||
<div class="left-panel">
|
||||
<div class="left-topbar">
|
||||
<el-input
|
||||
v-model="processSearch"
|
||||
placeholder="搜索工艺名称..."
|
||||
clearable
|
||||
size="small"
|
||||
prefix-icon="el-icon-search"
|
||||
class="left-search-input"
|
||||
@keyup.enter.native="handleProcessSearch"
|
||||
/>
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handleProcessAdd">新增</el-button>
|
||||
<el-button size="mini" :icon="filterExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'" @click="filterExpanded = !filterExpanded">
|
||||
{{ filterExpanded ? '收起' : '筛选' }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="left-filter" v-show="filterExpanded">
|
||||
<el-form :model="processFilters" size="small" label-width="56px">
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="processFilters.status" placeholder="全部" clearable style="width:100%">
|
||||
<el-option label="启用" :value="1" />
|
||||
<el-option label="停用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="mini" @click="handleProcessSearch">搜索</el-button>
|
||||
<el-button size="mini" @click="resetProcessFilters">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="left-list" v-loading="processLoading">
|
||||
<div
|
||||
v-for="item in processList"
|
||||
:key="item.processId"
|
||||
:class="['process-item', { active: selectedProcess && selectedProcess.processId === item.processId }]"
|
||||
@click="selectProcess(item)"
|
||||
>
|
||||
<div class="process-item-header">
|
||||
<div class="process-item-name">{{ item.processName }}</div>
|
||||
<div class="process-item-actions" @click.stop>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleProcessUpdate(item)" />
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleProcessDelete(item)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="process-item-meta">
|
||||
<span class="process-item-code">{{ item.processCode }}</span>
|
||||
<span :class="['process-item-status', item.status === 1 ? 'on' : 'off']">
|
||||
{{ item.status === 1 ? '启用' : '停用' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-if="!processLoading && processList.length === 0" description="暂无工艺路线" :image-size="50" />
|
||||
</div>
|
||||
|
||||
<pagination
|
||||
v-show="processTotal > 0"
|
||||
:total="processTotal"
|
||||
:page.sync="processQueryParams.pageNum"
|
||||
:limit.sync="processQueryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, prev, pager, next, sizes"
|
||||
:pager-count="3"
|
||||
small
|
||||
@pagination="getProcessList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ==================== 右侧面板:工序参数 ==================== -->
|
||||
<template #panelB>
|
||||
<div class="right-panel">
|
||||
<div v-if="!selectedProcess" class="empty-hint">
|
||||
<el-empty description="请从左侧列表选择一个工艺路线,查看和编辑其工序参数" :image-size="100" />
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div class="selected-process-info">
|
||||
<div class="process-info-left">
|
||||
<span class="process-info-name">{{ selectedProcess.processName }}</span>
|
||||
<span class="process-info-code">{{ selectedProcess.processCode }}</span>
|
||||
</div>
|
||||
<div class="process-info-right">
|
||||
<span v-if="selectedProcess.targetYield" class="process-info-tag">成材率 {{ selectedProcess.targetYield }}%</span>
|
||||
<span v-if="selectedProcess.standardCapacity" class="process-info-tag">产能 {{ selectedProcess.standardCapacity }}t/h</span>
|
||||
<span :class="['process-info-status', selectedProcess.status === 1 ? 'on' : 'off']">
|
||||
{{ selectedProcess.status === 1 ? '启用' : '停用' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-toolbar">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增参数</el-button>
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete()">删除</el-button>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="dataList"
|
||||
size="small"
|
||||
border
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="45" align="center" />
|
||||
<el-table-column v-for="col in stepColumns" :key="col.prop" v-bind="col">
|
||||
<template slot-scope="scope">
|
||||
<template v-if="editingId != null && editingId === scope.row.paramId">
|
||||
<el-input v-if="col.editType === 'input'" v-model="editForm[col.prop]" size="small" />
|
||||
<el-input-number v-else-if="col.editType === 'number'" v-model="editForm[col.prop]" size="small" :controls="false" style="width:100%" />
|
||||
<el-select v-else-if="col.editType === 'select'" v-model="editForm[col.prop]" size="small" style="width:100%">
|
||||
<el-option v-for="opt in col.options" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
<span v-else>{{ scope.row[col.prop] }}</span>
|
||||
</template>
|
||||
<span v-else>
|
||||
{{ col.formatter ? col.formatter(scope.row, col, scope.row[col.prop]) : scope.row[col.prop] }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="140" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<template v-if="editingId != null && editingId === scope.row.paramId">
|
||||
<el-button size="mini" type="text" style="color:#67c23a" @click="saveEdit(scope.row)">保存</el-button>
|
||||
<el-button size="mini" type="text" @click="cancelEdit()">取消</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="startEdit(scope.row)">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</DragResizePanel>
|
||||
|
||||
<!-- ==================== 参数新增弹窗 ==================== -->
|
||||
<el-dialog title="新增工序参数" :visible.sync="open" width="650px" append-to-body :close-on-click-modal="false">
|
||||
<el-form ref="form" :model="form" :rules="addRules" label-width="100px" size="small">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工序顺序" prop="stepOrder">
|
||||
<el-input-number v-model="form.stepOrder" :min="1" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工序名称" prop="stepName">
|
||||
<el-select v-model="form.stepName" placeholder="请选择" clearable style="width:100%">
|
||||
<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-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="参数编码" prop="paramCode">
|
||||
<el-input v-model="form.paramCode" placeholder="TEMP/SPEED/TENSION" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="参数名称" prop="paramNameZh">
|
||||
<el-input v-model="form.paramNameZh" placeholder="请输入中文名" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="参数分类" prop="paramCategory">
|
||||
<el-select v-model="form.paramCategory" placeholder="请选择" clearable style="width:100%">
|
||||
<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-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="单位" prop="unit">
|
||||
<el-input v-model="form.unit" placeholder="℃/m/min/MPa/A" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="最小值" prop="minValue">
|
||||
<el-input-number v-model="form.minValue" :controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="最大值" prop="maxValue">
|
||||
<el-input-number v-model="form.maxValue" :controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="目标值" prop="targetValue">
|
||||
<el-input-number v-model="form.targetValue" :controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="报警下限" prop="alarmMin">
|
||||
<el-input-number v-model="form.alarmMin" :controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="报警上限" prop="alarmMax">
|
||||
<el-input-number v-model="form.alarmMax" :controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否CCP" prop="isCritical">
|
||||
<el-select v-model="form.isCritical" clearable style="width:100%">
|
||||
<el-option label="是" :value="1" />
|
||||
<el-option label="否" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="排序" prop="sortOrder">
|
||||
<el-input-number v-model="form.sortOrder" :controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" size="small" @click="submitForm">确 定</el-button>
|
||||
<el-button size="small" @click="cancelAdd">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- ==================== 工艺新增/编辑弹窗 ==================== -->
|
||||
<el-dialog :title="processDialogTitle" :visible.sync="processDialogOpen" width="550px" append-to-body :close-on-click-modal="false">
|
||||
<el-form ref="processForm" :model="processForm" :rules="processRules" label-width="80px" size="small">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工艺代号" prop="processCode">
|
||||
<el-input v-model="processForm.processCode" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工艺名称" prop="processName">
|
||||
<el-input v-model="processForm.processName" placeholder="请输入工艺名称" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="适配产品">
|
||||
<el-input v-model="processForm.adaptProductType" placeholder="逗号分隔,如 CRC,GI" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="processForm.status" style="width:100%">
|
||||
<el-option label="启用" :value="1" />
|
||||
<el-option label="停用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="目标成材率">
|
||||
<el-input-number v-model="processForm.targetYield" :controls="false" style="width:100%">
|
||||
<template slot="suffix">%</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="标准产能">
|
||||
<el-input-number v-model="processForm.standardCapacity" :controls="false" style="width:100%">
|
||||
<template slot="suffix">t/h</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="工艺流程">
|
||||
<el-input v-model="processForm.flowOverview" type="textarea" :rows="3" placeholder="描述整体工艺流程" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="processForm.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" size="small" @click="submitProcessForm" :loading="processSubmitting">确 定</el-button>
|
||||
<el-button size="small" @click="cancelProcessDialog">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DragResizePanel from '@/components/DragResizePanel/index.vue'
|
||||
import {
|
||||
listProcesse, getProcesse, addProcesse, updateProcesse, delProcesse,
|
||||
listProcessStepParam, getProcessStepParam, addProcessStepParam, updateProcessStepParam, delProcessStepParam
|
||||
} from '@/api/pt/process'
|
||||
|
||||
const boolFormatter = (row, col, val) => (val === 1 || val === '1') ? '是' : '否'
|
||||
|
||||
const STEP_COLUMNS = [
|
||||
{ prop: 'stepOrder', label: '工序顺序', width: 80, editType: 'number' },
|
||||
{ prop: 'stepName', label: '工序名称', width: 90, editType: 'select',
|
||||
options: [{ label: '酸洗', value: '酸洗' }, { label: '冷轧', value: '冷轧' }, { label: '退火', value: '退火' }, { label: '镀锌', value: '镀锌' }, { label: '平整', value: '平整' }, { label: '拉矫', value: '拉矫' }] },
|
||||
{ prop: 'paramCode', label: '参数编码', width: 100, editType: 'input' },
|
||||
{ prop: 'paramNameZh', label: '参数名称', minWidth: 100, editType: 'input' },
|
||||
{ prop: 'paramCategory', label: '分类', width: 70, editType: 'select',
|
||||
options: [{ label: '温度', value: '温度' }, { label: '速度', value: '速度' }, { label: '压力', value: '压力' }, { label: '电流', value: '电流' }, { label: '张力', value: '张力' }] },
|
||||
{ prop: 'minValue', label: '最小值', width: 80, editType: 'number' },
|
||||
{ prop: 'maxValue', label: '最大值', width: 80, editType: 'number' },
|
||||
{ prop: 'targetValue', label: '目标值', width: 80, editType: 'number' },
|
||||
{ prop: 'unit', label: '单位', width: 60, editType: 'input' },
|
||||
{ prop: 'isCritical', label: 'CCP', width: 55, editType: 'select', formatter: boolFormatter,
|
||||
options: [{ label: '是', value: 1 }, { label: '否', value: 0 }] },
|
||||
{ prop: 'alarmMin', label: '报警下限', width: 80, editType: 'number' },
|
||||
{ prop: 'alarmMax', label: '报警上限', width: 80, editType: 'number' },
|
||||
{ prop: 'sortOrder', label: '排序', width: 55, editType: 'number' }
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'PtProcesse',
|
||||
components: { DragResizePanel },
|
||||
data() {
|
||||
return {
|
||||
// ===== 工艺列表 =====
|
||||
processLoading: false,
|
||||
processList: [],
|
||||
processTotal: 0,
|
||||
processQueryParams: { pageNum: 1, pageSize: 20 },
|
||||
processSearch: '',
|
||||
filterExpanded: false,
|
||||
processFilters: { status: null },
|
||||
selectedProcess: null,
|
||||
|
||||
// ===== 工艺弹窗 =====
|
||||
processDialogOpen: false,
|
||||
processDialogTitle: '',
|
||||
processForm: {},
|
||||
processSubmitting: false,
|
||||
processRules: {
|
||||
processName: [{ required: true, message: '请输入工艺名称', trigger: 'blur' }]
|
||||
},
|
||||
|
||||
// ===== 工序参数表格 =====
|
||||
loading: false,
|
||||
dataList: [],
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 20 },
|
||||
showSearch: true,
|
||||
ids: [],
|
||||
multiple: true,
|
||||
stepColumns: STEP_COLUMNS,
|
||||
|
||||
// ===== 行内编辑 =====
|
||||
editingId: null,
|
||||
editForm: {},
|
||||
editFormOriginal: null,
|
||||
|
||||
// ===== 新增弹窗 =====
|
||||
open: false,
|
||||
form: {},
|
||||
addRules: {
|
||||
stepOrder: [{ required: true, message: '请输入工序顺序', trigger: 'blur' }],
|
||||
stepName: [{ required: true, message: '请选择工序名称', trigger: 'change' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getProcessList()
|
||||
},
|
||||
methods: {
|
||||
// ==================== 工艺 CRUD ====================
|
||||
getProcessList() {
|
||||
this.processLoading = true
|
||||
const params = { ...this.processQueryParams }
|
||||
if (this.processSearch) params.processName = this.processSearch
|
||||
if (this.processFilters.status != null && this.processFilters.status !== '') {
|
||||
params.status = this.processFilters.status
|
||||
}
|
||||
listProcesse(params).then(res => {
|
||||
this.processList = res.rows || []
|
||||
this.processTotal = res.total || 0
|
||||
this.processLoading = false
|
||||
}).catch(() => { this.processLoading = false })
|
||||
},
|
||||
handleProcessSearch() {
|
||||
this.processQueryParams.pageNum = 1
|
||||
this.getProcessList()
|
||||
},
|
||||
resetProcessFilters() {
|
||||
this.processFilters = { status: null }
|
||||
this.processSearch = ''
|
||||
this.processQueryParams.pageNum = 1
|
||||
this.getProcessList()
|
||||
},
|
||||
selectProcess(item) {
|
||||
this.cancelEdit()
|
||||
this.selectedProcess = item
|
||||
this.resetQueryParams()
|
||||
this.getList()
|
||||
},
|
||||
handleProcessAdd() {
|
||||
const now = new Date()
|
||||
const code = 'PRC-' +
|
||||
now.getFullYear() + String(now.getMonth() + 1).padStart(2, '0') +
|
||||
String(now.getDate()).padStart(2, '0') + '-' +
|
||||
String(now.getHours()).padStart(2, '0') +
|
||||
String(now.getMinutes()).padStart(2, '0') +
|
||||
String(now.getSeconds()).padStart(2, '0')
|
||||
this.processForm = {
|
||||
processId: undefined, processCode: code, processName: '',
|
||||
adaptProductType: '', status: 1, targetYield: undefined,
|
||||
standardCapacity: undefined, flowOverview: '', remark: ''
|
||||
}
|
||||
this.processDialogTitle = '新增工艺路线'
|
||||
this.processDialogOpen = true
|
||||
this.processSubmitting = false
|
||||
this.$nextTick(() => { if (this.$refs['processForm']) this.$refs['processForm'].clearValidate() })
|
||||
},
|
||||
handleProcessUpdate(item) {
|
||||
const row = item || this.selectedProcess
|
||||
if (!row) return
|
||||
getProcesse(row.processId).then(res => {
|
||||
const d = res.data || {}
|
||||
this.processForm = {
|
||||
processId: d.processId, processCode: d.processCode || '',
|
||||
processName: d.processName || '', adaptProductType: d.adaptProductType || '',
|
||||
status: d.status != null ? d.status : 1,
|
||||
targetYield: d.targetYield, standardCapacity: d.standardCapacity,
|
||||
flowOverview: d.flowOverview || '', remark: d.remark || ''
|
||||
}
|
||||
this.processDialogTitle = '修改工艺路线'
|
||||
this.processDialogOpen = true
|
||||
this.processSubmitting = false
|
||||
this.$nextTick(() => { if (this.$refs['processForm']) this.$refs['processForm'].clearValidate() })
|
||||
})
|
||||
},
|
||||
handleProcessDelete(item) {
|
||||
const row = item || this.selectedProcess
|
||||
if (!row) return
|
||||
this.$modal.confirm('确认删除工艺「' + row.processName + '」?').then(() => {
|
||||
return delProcesse(row.processId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
if (this.selectedProcess && this.selectedProcess.processId === row.processId) {
|
||||
this.selectedProcess = null; this.dataList = []; this.total = 0
|
||||
}
|
||||
this.getProcessList()
|
||||
}).catch(() => {})
|
||||
},
|
||||
submitProcessForm() {
|
||||
this.$refs['processForm'].validate(valid => {
|
||||
if (!valid) return
|
||||
this.processSubmitting = true
|
||||
const d = this.processForm
|
||||
const act = d.processId ? updateProcesse(d) : addProcesse(d)
|
||||
act.then(() => {
|
||||
this.$modal.msgSuccess(d.processId ? '修改成功' : '新增成功')
|
||||
this.processDialogOpen = false
|
||||
this.processSubmitting = false
|
||||
this.getProcessList()
|
||||
if (d.processId && this.selectedProcess && this.selectedProcess.processId === d.processId) {
|
||||
getProcesse(d.processId).then(res => { this.selectedProcess = res.data })
|
||||
}
|
||||
}).catch(() => { this.processSubmitting = false })
|
||||
})
|
||||
},
|
||||
cancelProcessDialog() {
|
||||
this.processDialogOpen = false
|
||||
},
|
||||
|
||||
// ==================== 工序参数 CRUD ====================
|
||||
resetQueryParams() {
|
||||
this.queryParams = { pageNum: 1, pageSize: 20, processId: this.selectedProcess ? this.selectedProcess.processId : undefined }
|
||||
this.ids = []
|
||||
this.multiple = true
|
||||
},
|
||||
getList() {
|
||||
if (!this.selectedProcess) return
|
||||
this.loading = true
|
||||
const params = { ...this.queryParams, processId: this.selectedProcess.processId }
|
||||
listProcessStepParam(params).then(res => {
|
||||
this.dataList = res.rows || []
|
||||
this.total = res.total || 0
|
||||
this.loading = false
|
||||
}).catch(() => { this.loading = false })
|
||||
},
|
||||
handleSelectionChange(sel) {
|
||||
this.ids = sel.map(i => i.paramId)
|
||||
this.multiple = !sel.length
|
||||
},
|
||||
|
||||
handleAdd() {
|
||||
this.cancelEdit()
|
||||
this.form = { processId: this.selectedProcess.processId }
|
||||
this.open = true
|
||||
this.$nextTick(() => { if (this.$refs['form']) this.$refs['form'].clearValidate() })
|
||||
},
|
||||
cancelAdd() { this.open = false },
|
||||
submitForm() {
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (!valid) return
|
||||
addProcessStepParam(this.form).then(() => {
|
||||
this.$modal.msgSuccess('新增成功')
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
const ids = row ? row.paramId : this.ids.join(',')
|
||||
if (!ids) { this.$modal.msgWarning('请选择要删除的记录'); return }
|
||||
this.$modal.confirm('确认删除?').then(() => delProcessStepParam(ids)).then(() => {
|
||||
this.getList(); this.$modal.msgSuccess('删除成功')
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// ==================== 行内编辑 ====================
|
||||
startEdit(row) {
|
||||
const form = {}
|
||||
this.stepColumns.forEach(c => { form[c.prop] = row[c.prop] })
|
||||
form.paramId = row.paramId
|
||||
form.processId = row.processId
|
||||
this.editForm = form
|
||||
this.editFormOriginal = JSON.parse(JSON.stringify(row))
|
||||
this.editingId = row.paramId
|
||||
},
|
||||
cancelEdit() {
|
||||
this.editingId = null
|
||||
this.editForm = {}
|
||||
this.editFormOriginal = null
|
||||
},
|
||||
saveEdit(row) {
|
||||
const data = { ...this.editForm }
|
||||
const idx = this.dataList.findIndex(r => r.paramId === row.paramId)
|
||||
if (idx >= 0) this.dataList.splice(idx, 1, { ...this.dataList[idx], ...data })
|
||||
this.editingId = null
|
||||
this.editForm = {}
|
||||
const original = this.editFormOriginal
|
||||
this.editFormOriginal = null
|
||||
updateProcessStepParam(data).then(() => {
|
||||
this.$modal.msgSuccess('保存成功')
|
||||
}).catch(() => {
|
||||
if (idx >= 0 && original) this.dataList.splice(idx, 1, original)
|
||||
this.$modal.msgError('保存失败,已还原')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pt-process-page {
|
||||
height: calc(100vh - 84px);
|
||||
|
||||
::v-deep .left-panel .pagination-container {
|
||||
padding: 4px 8px;
|
||||
.el-pagination {
|
||||
flex-wrap: wrap; justify-content: center;
|
||||
.el-pagination__total { font-size: 11px; }
|
||||
.el-pagination__sizes { margin: 0 2px; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 左侧面板 =====
|
||||
.left-panel {
|
||||
height: 100%; display: flex; flex-direction: column;
|
||||
background: #fff; border-right: 1px solid #e8e8e8;
|
||||
|
||||
.left-topbar {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
padding: 8px 10px; border-bottom: 1px solid #ebeef5;
|
||||
.left-search-input { flex: 1; }
|
||||
}
|
||||
.left-filter {
|
||||
padding: 8px 10px; border-bottom: 1px solid #ebeef5; background: #fafafa;
|
||||
::v-deep .el-form-item { margin-bottom: 6px; }
|
||||
::v-deep .el-form-item__label { font-size: 11px; }
|
||||
}
|
||||
.left-list {
|
||||
flex: 1; overflow-y: auto;
|
||||
.process-item {
|
||||
padding: 10px 12px; cursor: pointer;
|
||||
border-bottom: 1px solid #f0f2f5; transition: all 0.15s;
|
||||
&:hover { background: #f5f7fa; .process-item-actions { opacity: 1; } }
|
||||
&.active {
|
||||
background: #ecf5ff; border-left: 3px solid #409EFF; padding-left: 9px;
|
||||
.process-item-name { color: #409EFF; }
|
||||
}
|
||||
&:last-child { border-bottom: none; }
|
||||
}
|
||||
.process-item-header {
|
||||
display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px;
|
||||
}
|
||||
.process-item-name {
|
||||
font-size: 13px; font-weight: 600; color: #303133;
|
||||
flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.4;
|
||||
}
|
||||
.process-item-actions {
|
||||
opacity: 0; flex-shrink: 0; transition: opacity 0.15s;
|
||||
.el-button + .el-button { margin-left: 0; }
|
||||
}
|
||||
.process-item-meta { display: flex; align-items: center; gap: 6px; }
|
||||
.process-item-code {
|
||||
font-size: 11px; color: #909399; font-family: 'SF Mono', 'Menlo', monospace;
|
||||
background: #f5f7fa; padding: 1px 6px; border-radius: 3px;
|
||||
}
|
||||
.process-item-status {
|
||||
font-size: 10px; padding: 1px 6px; border-radius: 3px;
|
||||
&.on { color: #67c23a; background: #f0f9eb; }
|
||||
&.off { color: #909399; background: #f4f4f5; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 右侧面板 =====
|
||||
.right-panel {
|
||||
height: 100%; display: flex; flex-direction: column;
|
||||
background: #fff; padding: 0 12px 12px; overflow: auto;
|
||||
}
|
||||
|
||||
.selected-process-info {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
margin: 10px 0 8px; padding: 10px 14px; background: #fff;
|
||||
border: 1px solid #e4e7ed; border-left: 4px solid #409EFF;
|
||||
border-radius: 0 6px 6px 0; box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
flex-shrink: 0; gap: 12px;
|
||||
|
||||
.process-info-left { display: flex; align-items: center; gap: 10px; min-width: 0; }
|
||||
.process-info-name { font-size: 15px; font-weight: 700; color: #303133; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.process-info-code {
|
||||
font-size: 11px; font-family: 'SF Mono', 'Menlo', monospace; color: #909399;
|
||||
background: #f5f7fa; border: 1px solid #e4e7ed; padding: 2px 8px; border-radius: 4px; white-space: nowrap; flex-shrink: 0;
|
||||
}
|
||||
.process-info-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
|
||||
.process-info-tag {
|
||||
font-size: 11px; padding: 2px 8px; border-radius: 4px; line-height: 18px;
|
||||
color: #409EFF; background: #ecf5ff; border: 1px solid #d9ecff;
|
||||
}
|
||||
.process-info-status {
|
||||
font-size: 11px; padding: 2px 8px; border-radius: 4px; white-space: nowrap; line-height: 18px;
|
||||
&.on { color: #67c23a; background: #f0f9eb; border: 1px solid #e1f3d8; }
|
||||
&.off { color: #909399; background: #f4f4f5; border: 1px solid #e9e9eb; }
|
||||
}
|
||||
}
|
||||
|
||||
.empty-hint { display: flex; justify-content: center; align-items: center; flex: 1; }
|
||||
|
||||
.tab-toolbar {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 6px 0; flex-shrink: 0;
|
||||
.right-toolbar { margin-left: auto; }
|
||||
}
|
||||
</style>
|
||||
0
klp-ui/src/views/pt/product/index.vue
Normal file
0
klp-ui/src/views/pt/product/index.vue
Normal file
1319
klp-ui/src/views/pt/standard/index.vue
Normal file
1319
klp-ui/src/views/pt/standard/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user