@ -542,34 +542,16 @@ const getOrGenerateTempBomNo = (): string => {
}
const handleCreate = async () => {
// 1. 全局拦截
const isIntercepted = await checkAndInterceptGlobalDraft()
if (isIntercepted) return
// 2. 正常的纯新建逻辑
resetForm()
const tempBomNo = getOrGenerateTempBomNo()
pendingDraftBomN o = tempBomNo
pendingDraftVersion = 'V1.0'
form.bom_n o = tempBomNo
originalDraftHash.value = getDraftHash()
try {
const res = await getDraftDetail({ bom_no: pendingDraftBomNo, version: pendingDraftVersion })
if (res.code === 200 && res.data) {
const confirm = await ElMessageBox.confirm(
'检测到未发布的草稿,是否恢复继续编辑?',
'草稿恢复',
{ confirmButtonText: '恢复草稿', cancelButtonText: '放弃草稿', type: 'info' }
).catch(() => null)
if (confirm) {
restoreDraftToForm(res.data)
dialogTitle.value = '新建 BOM'
isEditMode.value = false
isSaveAsMode.value = false
isReadOnlyMode.value = false
dialogVisible.value = true
return
} else {
resetForm()
}
}
} catch (e) {}
resetForm()
dialogTitle.value = '新建 BOM'
isEditMode.value = false
isSaveAsMode.value = false
@ -578,45 +560,16 @@ const handleCreate = async () => {
}
const saveDraftData = async () => {
// 获取当前正在编辑的单号
const draftBomNo = form.bom_no || getOrGenerateTempBomNo()
const currentHash = getDraftHash()
// 场景 A: 之前已经存过/恢复过草稿,且没有任何改动
// 场景 A: 防呆拦截。如果数据没有任何改动,直接提示并阻断多余的网络请求
if (originalDraftHash.value && currentHash === originalDraftHash.value) {
return ElMessage.warning('草稿数据无变动,无需重复暂存')
}
// 场景 B: 已经存过草稿,且发生了改动 -> 询问覆盖还是新建
if (originalDraftHash.value && currentHash !== originalDraftHash.value) {
try {
const action = await ElMessageBox.confirm(
'检测到草稿内容已发生变动,请选择保存方式:',
'草稿变动提示',
{
confirmButtonText: '直接覆盖',
cancelButtonText: '另存为新草稿',
distinguishCancelAndClose: true,
type: 'warning'
}
)
if (action === 'confirm') {
// 选择覆盖原草稿
await executeSaveDraftRequest(draftBomNo)
}
} catch (action) {
if (action === 'cancel') {
// 选择另存为新草稿:生成新单号并保存
const ts = new Date().toISOString().replace(/[-T:.Z]/g, '').slice(0, 14)
const uid = Math.random().toString(36).slice(2, 6)
const newTempNo = `DRAFT-TEMP-${ts}-${uid}`
form.bom_no = newTempNo
await executeSaveDraftRequest(newTempNo)
}
}
return
}
// 场景 C: 第一次暂存
// 场景 B: 执行保存。在" 全局唯一草稿 " 架构下 , 不再询问 , 直接实时同步最新状态到数据库
await executeSaveDraftRequest ( draftBomNo )
}
@ -642,6 +595,7 @@ const executeSaveDraftRequest = async (targetBomNo: string) => {
ElMessage . success ( '草稿暂存成功' )
form . bom _no = targetBomNo
localStorage . setItem ( 'pending_bom_draft_no' , targetBomNo )
localStorage . setItem ( 'pending_bom_draft_version' , draftVersion )
originalDraftHash . value = getDraftHash ( )
} else {
ElMessage . error ( res . msg || '暂存失败' )
@ -677,6 +631,71 @@ const restoreDraftToForm = (draftData: any) => {
originalDraftHash . value = getDraftHash ( )
}
const checkUserDraft = async ( bomNo : string , version : string ) => {
try {
const res = await getDraftDetail ( { bom _no : bomNo , version : version } )
if ( res . code === 200 && res . data ) {
const confirm = await ElMessageBox . confirm (
` 检测到未发布的草稿数据,是否恢复继续编辑? ` ,
'草稿恢复' ,
{ confirmButtonText : '恢复草稿' , cancelButtonText : '放弃草稿' , type : 'info' }
) . catch ( ( ) => 'cancel' )
if ( confirm === 'confirm' ) {
return res . data
}
}
} catch ( e ) {
// 网络异常或查不到均视为无草稿
}
return null
}
const checkAndInterceptGlobalDraft = async ( ) : Promise < boolean > => {
const pendingNo = localStorage . getItem ( 'pending_bom_draft_no' )
const pendingVer = localStorage . getItem ( 'pending_bom_draft_version' ) || 'V1.0'
if ( pendingNo ) {
try {
const res = await getDraftDetail ( { bom _no : pendingNo , version : pendingVer } )
if ( res . code === 200 && res . data ) {
const action = await ElMessageBox . confirm (
` 系统检测到您有一个未发布的草稿 [ ${ pendingNo } ]。 \ n \ n为防止数据混乱, 同一时间只允许保留一份草稿。 \ n• 点击【恢复草稿】继续编辑 \ n• 点击【放弃旧草稿】彻底销毁它并开启新任务 ` ,
'全局草稿拦截' ,
{
confirmButtonText : '恢复草稿' ,
cancelButtonText : '放弃旧草稿' ,
distinguishCancelAndClose : true ,
type : 'warning'
}
) . catch ( action => action )
if ( action === 'confirm' ) {
resetForm ( )
restoreDraftToForm ( res . data )
originalDraftHash . value = getDraftHash ( )
dialogTitle . value = '继续编辑草稿'
isEditMode . value = false
isSaveAsMode . value = false
isReadOnlyMode . value = false
dialogVisible . value = true
return true
} else if ( action === 'cancel' ) {
localStorage . removeItem ( 'pending_bom_draft_no' )
localStorage . removeItem ( 'pending_bom_draft_version' )
return false
} else {
return true
}
}
} catch ( e ) {
localStorage . removeItem ( 'pending_bom_draft_no' )
localStorage . removeItem ( 'pending_bom_draft_version' )
}
}
return false
}
const handleView = async ( row : BomItem ) => {
await loadDetail ( row . bom _no , row . version )
dialogTitle . value = '查看 BOM'
@ -686,16 +705,17 @@ const handleView = async (row: BomItem) => {
dialogVisible . value = true
}
const handleSaveAs = async (row: BomItem) => {
// 1. 重置 form 基础状态
resetForm()
const handleSaveAs = async ( row : any ) => {
// 1. 全局拦截
const isIntercepted = await checkAndInterceptGlobalDraft ( )
if ( isIntercepted ) return
// 2. 获取源 BOM 详情(不通过 loadDetail, 显式走" 深拷贝 + 清 ID "路径)
// 2. 正常的纯另存为逻辑
resetForm ( )
const res = await getBomDetail ( row . bom _no , row . version )
if ( res . code !== 200 ) return
const raw = JSON . parse ( JSON . stringify ( res . data ) )
// 3. ★ 核心:显式深拷贝 + 清除所有主键 ID( 防止后端误判为更新操作)
if ( 'id' in raw ) delete raw . id
if ( 'bom_id' in raw ) delete raw . bom _id
if ( Array . isArray ( raw . children ) ) {
@ -705,7 +725,6 @@ const handleSaveAs = async (row: BomItem) => {
} )
}
// 4. 把" 已清除 ID 的纯净数据 "写入 form
form . children = raw . children . map ( ( child : any , idx : number ) => ( {
rowKey : idx ,
child _id : child . child _id ,
@ -718,18 +737,18 @@ const handleSaveAs = async (row: BomItem) => {
form . parent _id = raw . parent _id
parentNameInput . value = raw . parent _name || '未知产品'
}
form . bom _no = ( raw . parent _spec || row . bom _no ) . split ( '/' ) [ 0 ] . trim ( )
form . remark = raw . remark || ''
form . versionUpgradeType = 'minor'
form . version = versionOptions . value ? . minor || 'V1.1'
// 5. 设置" 另存为 "模式特有状态(版本升级单选 + 子件变更检测)
originalVersion = raw . version || ''
currentBomNo = row . bom _no
originalChildren = JSON . parse ( JSON . stringify ( form . children ) )
f orm.versionUpgradeType = 'minor'
form.version = versionOptions.value.minor
originalDraftHash . value = getDraftHash ( )
// 6. 弹窗状态机:标题" 新增 BOM " , 父件可改 , 启用 版本升级单选
dialogTitle . value = '新增 BOM'
dialogTitle . value = '新增 BOM ( 版本升级)'
isEditMode . value = false
isSaveAsMode . value = true
isReadOnlyMode . value = false
@ -844,6 +863,7 @@ const submitForm = async () => {
if ( res . code === 200 ) {
ElMessage . success ( '发布成功' )
localStorage . removeItem ( 'pending_bom_draft_no' )
localStorage . removeItem ( 'pending_bom_draft_version' )
originalDraftHash . value = ''
dialogVisible . value = false
fetchBomList ( )