3 changed files with 294 additions and 8 deletions
-
2src/api/part/partInfo.js
-
279src/views/modules/srmPart/PartAdvancedCopyDialog.vue
-
21src/views/modules/srmPart/partInfoList.vue
@ -0,0 +1,279 @@ |
|||||
|
<template> |
||||
|
<!-- 上下源/目标分区,操作按钮统一放底部 footer,沿用页面现有 Element 风格 - rqrq --> |
||||
|
<el-dialog |
||||
|
title="高级复制" |
||||
|
:visible.sync="visible" |
||||
|
width="840px" |
||||
|
top="8vh" |
||||
|
:close-on-click-modal="false" |
||||
|
:close-on-press-escape="!saveLoading" |
||||
|
:show-close="!saveLoading" |
||||
|
class="advanced-copy-dialog" |
||||
|
v-drag> |
||||
|
<div class="advanced-copy-layout"> |
||||
|
<div class="advanced-copy-fields"> |
||||
|
<fieldset class="copy-section"> |
||||
|
<legend>源物料信息</legend> |
||||
|
<el-form :model="source" label-position="top" disabled> |
||||
|
<el-row :gutter="16"> |
||||
|
<el-col :span="6"> |
||||
|
<el-form-item label="工厂编号"><el-input v-model="source.site" /></el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="10"> |
||||
|
<el-form-item label="基准料号"><el-input v-model="source.basePartNo" /></el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<el-form-item label="物料后缀"><el-input v-model="source.partSuffix" /></el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="16"> |
||||
|
<el-col :span="14"> |
||||
|
<el-form-item label="物料名称"><el-input v-model="source.partDesc" /></el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="10"> |
||||
|
<el-form-item label="规格型号"><el-input v-model="source.partSpec" /></el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-form> |
||||
|
</fieldset> |
||||
|
|
||||
|
<fieldset class="copy-section"> |
||||
|
<legend>目标物料信息</legend> |
||||
|
<el-form ref="targetForm" :model="form" :rules="rules" :disabled="saveLoading" label-position="top"> |
||||
|
<el-row :gutter="16"> |
||||
|
<el-col :span="6"> |
||||
|
<el-form-item label="工厂编号"><el-input v-model="form.site" disabled /></el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="10"> |
||||
|
<el-form-item label="基准料号" prop="basePartNo"> |
||||
|
<el-input v-model="form.basePartNo" maxlength="30" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<el-form-item label="物料后缀" prop="partSuffix"> |
||||
|
<el-input v-model="form.partSuffix" maxlength="29" placeholder="可不填" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="16"> |
||||
|
<el-col :span="14"> |
||||
|
<el-form-item label="物料名称" prop="partDesc"> |
||||
|
<el-input v-model="form.partDesc" maxlength="255" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="10"> |
||||
|
<el-form-item label="规格型号" prop="partSpec"> |
||||
|
<el-input v-model="form.partSpec" maxlength="50" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-form> |
||||
|
<div class="target-part-no">目标物料编码:{{ targetPartNo || '—' }}</div> |
||||
|
</fieldset> |
||||
|
|
||||
|
<fieldset class="copy-section copy-options"> |
||||
|
<legend>复制项目</legend> |
||||
|
<!-- 固定项不提交开关,后端始终复制主档和属性;两个可选项默认不勾选 - rqrq --> |
||||
|
<el-checkbox :value="true" disabled>物料信息+属性</el-checkbox> |
||||
|
<el-checkbox v-model="form.copySupplier" :disabled="saveLoading">供应商可供物料+价格表</el-checkbox> |
||||
|
<el-checkbox v-model="form.copyInspectionTemplate" :disabled="saveLoading">检验模板</el-checkbox> |
||||
|
</fieldset> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 与其他弹框一致,底部横向排列保存和关闭;保留提交期间的禁用状态 - rqrq --> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" :loading="saveLoading" :disabled="saveLoading" @click="save">保存</el-button> |
||||
|
<el-button :disabled="saveLoading" @click="visible = false">关闭</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { advancedCopyPart } from '@/api/part/partInfo' |
||||
|
|
||||
|
export default { |
||||
|
name: 'PartAdvancedCopyDialog', |
||||
|
data () { |
||||
|
return { |
||||
|
visible: false, |
||||
|
saveLoading: false, |
||||
|
source: {}, |
||||
|
form: {}, |
||||
|
rules: { |
||||
|
basePartNo: [{ required: true, whitespace: true, message: '请输入基准料号', trigger: 'blur' }], |
||||
|
partDesc: [{ required: true, whitespace: true, message: '请输入物料名称', trigger: 'blur' }], |
||||
|
partSpec: [{ required: true, whitespace: true, message: '请输入规格型号', trigger: 'blur' }] |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
// 预览与后端一致:基准料号必填,后缀空白时不追加连字符 - rqrq |
||||
|
targetPartNo () { |
||||
|
const base = (this.form.basePartNo || '').trim().toUpperCase() |
||||
|
const suffix = (this.form.partSuffix || '').trim().toUpperCase() |
||||
|
return base ? base + (suffix ? `-${suffix}` : '') : '' |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
/** 以当前选中行作为唯一复制源;打开时重新初始化,避免沿用上次勾选或目标输入 - rqrq */ |
||||
|
open (row) { |
||||
|
if (!row || !row.partNo) { |
||||
|
this.$message.warning('请先选择源物料') |
||||
|
return |
||||
|
} |
||||
|
const site = (this.$store.state.user.site || '').trim().toUpperCase() |
||||
|
if (!site || (row.site || '').trim().toUpperCase() !== site) { |
||||
|
this.$message.warning('请选择当前工厂的物料') |
||||
|
return |
||||
|
} |
||||
|
const partNo = row.partNo.trim().toUpperCase() |
||||
|
// 主档未维护基准料号时,上下区域均带出完整物料编码,不按 '-' 拆分 - rqrq |
||||
|
const storedBase = (row.basePartNo || '').trim().toUpperCase() |
||||
|
const base = storedBase || partNo |
||||
|
// 仅主档已有基准料号且编码匹配时提取后缀;空基准料号的物料后缀始终为空 - rqrq |
||||
|
const suffix = storedBase && partNo.indexOf(`${storedBase}-`) === 0 ? partNo.substring(storedBase.length + 1) : '' |
||||
|
this.source = { |
||||
|
site, |
||||
|
partNo, |
||||
|
basePartNo: base, |
||||
|
partSuffix: suffix, |
||||
|
partDesc: row.partDesc || '', |
||||
|
partSpec: row.partSpec || '' |
||||
|
} |
||||
|
this.form = { |
||||
|
site, |
||||
|
sourcePartNo: partNo, |
||||
|
basePartNo: base, |
||||
|
partSuffix: suffix, |
||||
|
partDesc: row.partDesc || '', |
||||
|
partSpec: row.partSpec || '', |
||||
|
copySupplier: false, |
||||
|
copyInspectionTemplate: false |
||||
|
} |
||||
|
this.visible = true |
||||
|
this.$nextTick(() => { |
||||
|
if (this.$refs.targetForm) this.$refs.targetForm.clearValidate() |
||||
|
}) |
||||
|
}, |
||||
|
/** 保存前校验编码;后台先检查源配置,目标存在时才返回覆盖确认,取消不会写入 - rqrq */ |
||||
|
save () { |
||||
|
if (this.saveLoading) return |
||||
|
// 工厂切换后必须重新选择源物料,避免弹框显示的工厂与实际提交工厂不一致 - rqrq |
||||
|
if ((this.$store.state.user.site || '').trim().toUpperCase() !== this.source.site) { |
||||
|
this.$message.warning('当前工厂已变化,请关闭弹框后重新选择源物料') |
||||
|
return |
||||
|
} |
||||
|
this.$refs.targetForm.validate(valid => { |
||||
|
if (!valid) return |
||||
|
const suffix = (this.form.partSuffix || '').trim().toUpperCase() |
||||
|
if (suffix.includes('-')) { |
||||
|
this.$message.warning('物料后缀不能包含 "-"') |
||||
|
return |
||||
|
} |
||||
|
if (this.targetPartNo.length > 30) { |
||||
|
this.$message.warning('目标物料编码不能超过30个字符') |
||||
|
return |
||||
|
} |
||||
|
if (this.targetPartNo === this.source.partNo) { |
||||
|
this.$message.warning('目标物料编码不能与源物料相同') |
||||
|
return |
||||
|
} |
||||
|
// 固定本次提交快照,确认覆盖期间锁住表单,避免确认的目标与实际提交不一致。 |
||||
|
const request = { |
||||
|
...this.form, |
||||
|
site: this.$store.state.user.site, |
||||
|
sourcePartNo: this.source.partNo, |
||||
|
basePartNo: this.form.basePartNo.trim().toUpperCase(), |
||||
|
partSuffix: suffix, |
||||
|
partDesc: this.form.partDesc.trim(), |
||||
|
partSpec: this.form.partSpec.trim(), |
||||
|
overwriteExisting: false |
||||
|
} |
||||
|
this.submitCopy(request) |
||||
|
}) |
||||
|
}, |
||||
|
/** 执行复制及一次覆盖确认;失败保留弹框输入,成功关闭并通知物料清单刷新 - rqrq */ |
||||
|
async submitCopy (request) { |
||||
|
this.saveLoading = true |
||||
|
try { |
||||
|
let { data } = await advancedCopyPart(request) |
||||
|
if (!data || data.code !== 0) { |
||||
|
this.$alert((data && data.msg) || '复制失败', '错误', { confirmButtonText: '确定' }) |
||||
|
return |
||||
|
} |
||||
|
if (data.row && data.row.overwriteRequired) { |
||||
|
try { |
||||
|
await this.$confirm(`目标物料【${data.row.partNo}】已经存在,是否覆盖?`, '提示', { |
||||
|
confirmButtonText: '覆盖', |
||||
|
cancelButtonText: '取消', |
||||
|
closeOnClickModal: false, |
||||
|
type: 'warning' |
||||
|
}) |
||||
|
} catch (cancel) { |
||||
|
// 取消覆盖时不再次请求,后台第一次请求也未写入任何数据。 |
||||
|
return |
||||
|
} |
||||
|
const response = await advancedCopyPart({ ...request, overwriteExisting: true }) |
||||
|
data = response.data |
||||
|
if (!data || data.code !== 0) { |
||||
|
this.$alert((data && data.msg) || '复制失败', '错误', { confirmButtonText: '确定' }) |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
this.$message.success(`复制成功,物料编码:${data.row.partNo}`) |
||||
|
this.visible = false |
||||
|
this.$emit('copied') |
||||
|
} catch (error) { |
||||
|
this.$message.error('复制失败:' + (error.message || '请稍后重试')) |
||||
|
} finally { |
||||
|
this.saveLoading = false |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* 保留原有控件外观,内容分区占满宽度,按钮使用标准 footer 布局 - rqrq */ |
||||
|
.advanced-copy-fields { |
||||
|
min-width: 0; |
||||
|
} |
||||
|
.copy-section { |
||||
|
margin: 0 0 16px; |
||||
|
padding: 8px 16px 16px; |
||||
|
border: 1px solid #DCDFE6; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
.copy-section legend { |
||||
|
padding: 0 6px; |
||||
|
color: #303133; |
||||
|
} |
||||
|
.copy-section /deep/ .el-form-item { |
||||
|
margin-bottom: 16px; |
||||
|
} |
||||
|
.copy-section /deep/ .el-input { |
||||
|
width: 100%; |
||||
|
} |
||||
|
.target-part-no { |
||||
|
color: #606266; |
||||
|
overflow-wrap: break-word; |
||||
|
} |
||||
|
.copy-options { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 12px 20px; |
||||
|
margin-bottom: 0; |
||||
|
} |
||||
|
.copy-options .el-checkbox { |
||||
|
margin-left: 0; |
||||
|
margin-right: 0; |
||||
|
} |
||||
|
.advanced-copy-dialog /deep/ .el-dialog { |
||||
|
max-width: calc(100vw - 32px); |
||||
|
} |
||||
|
.advanced-copy-dialog /deep/ .el-dialog__body { |
||||
|
/* 为弹框标题和底部按钮预留高度,长内容只在 body 内滚动 - rqrq */ |
||||
|
max-height: calc(84vh - 130px); |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue