BomManage: saveDraftData 简化为全局唯一草稿静默覆盖模式

This commit is contained in:
DXC
2026-06-10 12:11:53 +08:00
parent 74bc751624
commit 6686747e57

View File

@ -542,34 +542,16 @@ const getOrGenerateTempBomNo = (): string => {
} }
const handleCreate = async () => { const handleCreate = async () => {
// 1. 全局拦截
const isIntercepted = await checkAndInterceptGlobalDraft()
if (isIntercepted) return
// 2. 正常的纯新建逻辑
resetForm()
const tempBomNo = getOrGenerateTempBomNo() const tempBomNo = getOrGenerateTempBomNo()
pendingDraftBomNo = tempBomNo form.bom_no = tempBomNo
pendingDraftVersion = 'V1.0' 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' dialogTitle.value = '新建 BOM'
isEditMode.value = false isEditMode.value = false
isSaveAsMode.value = false isSaveAsMode.value = false
@ -578,45 +560,16 @@ const handleCreate = async () => {
} }
const saveDraftData = async () => { const saveDraftData = async () => {
// 获取当前正在编辑的单号
const draftBomNo = form.bom_no || getOrGenerateTempBomNo() const draftBomNo = form.bom_no || getOrGenerateTempBomNo()
const currentHash = getDraftHash() const currentHash = getDraftHash()
// 场景 A之前已经存过/恢复过草稿,且没有任何改动 // 场景 A防呆拦截。如果数据没有任何改动,直接提示并阻断多余的网络请求
if (originalDraftHash.value && currentHash === originalDraftHash.value) { if (originalDraftHash.value && currentHash === originalDraftHash.value) {
return ElMessage.warning('草稿数据无变动,无需重复暂存') return ElMessage.warning('草稿数据无变动,无需重复暂存')
} }
// 场景 B已经存过草稿,且发生了改动 -> 询问覆盖还是新建 // 场景 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第一次暂存
await executeSaveDraftRequest(draftBomNo) await executeSaveDraftRequest(draftBomNo)
} }
@ -642,6 +595,7 @@ const executeSaveDraftRequest = async (targetBomNo: string) => {
ElMessage.success('草稿暂存成功') ElMessage.success('草稿暂存成功')
form.bom_no = targetBomNo form.bom_no = targetBomNo
localStorage.setItem('pending_bom_draft_no', targetBomNo) localStorage.setItem('pending_bom_draft_no', targetBomNo)
localStorage.setItem('pending_bom_draft_version', draftVersion)
originalDraftHash.value = getDraftHash() originalDraftHash.value = getDraftHash()
} else { } else {
ElMessage.error(res.msg || '暂存失败') ElMessage.error(res.msg || '暂存失败')
@ -677,6 +631,71 @@ const restoreDraftToForm = (draftData: any) => {
originalDraftHash.value = getDraftHash() 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) => { const handleView = async (row: BomItem) => {
await loadDetail(row.bom_no, row.version) await loadDetail(row.bom_no, row.version)
dialogTitle.value = '查看 BOM' dialogTitle.value = '查看 BOM'
@ -686,16 +705,17 @@ const handleView = async (row: BomItem) => {
dialogVisible.value = true dialogVisible.value = true
} }
const handleSaveAs = async (row: BomItem) => { const handleSaveAs = async (row: any) => {
// 1. 重置 form 基础状态 // 1. 全局拦截
resetForm() const isIntercepted = await checkAndInterceptGlobalDraft()
if (isIntercepted) return
// 2. 获取源 BOM 详情(不通过 loadDetail显式走"深拷贝+ ID"路径) // 2. 正常的纯另存为逻辑
resetForm()
const res = await getBomDetail(row.bom_no, row.version) const res = await getBomDetail(row.bom_no, row.version)
if (res.code !== 200) return if (res.code !== 200) return
const raw = JSON.parse(JSON.stringify(res.data)) const raw = JSON.parse(JSON.stringify(res.data))
// 3. ★ 核心:显式深拷贝 + 清除所有主键 ID防止后端误判为更新操作
if ('id' in raw) delete raw.id if ('id' in raw) delete raw.id
if ('bom_id' in raw) delete raw.bom_id if ('bom_id' in raw) delete raw.bom_id
if (Array.isArray(raw.children)) { 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) => ({ form.children = raw.children.map((child: any, idx: number) => ({
rowKey: idx, rowKey: idx,
child_id: child.child_id, child_id: child.child_id,
@ -718,18 +737,18 @@ const handleSaveAs = async (row: BomItem) => {
form.parent_id = raw.parent_id form.parent_id = raw.parent_id
parentNameInput.value = raw.parent_name || '未知产品' parentNameInput.value = raw.parent_name || '未知产品'
} }
form.bom_no = (raw.parent_spec || row.bom_no).split('/')[0].trim() form.bom_no = (raw.parent_spec || row.bom_no).split('/')[0].trim()
form.remark = raw.remark || '' form.remark = raw.remark || ''
form.versionUpgradeType = 'minor'
form.version = versionOptions.value?.minor || 'V1.1'
// 5. 设置"另存为"模式特有状态(版本升级单选 + 子件变更检测)
originalVersion = raw.version || '' originalVersion = raw.version || ''
currentBomNo = row.bom_no currentBomNo = row.bom_no
originalChildren = JSON.parse(JSON.stringify(form.children)) originalChildren = JSON.parse(JSON.stringify(form.children))
form.versionUpgradeType = 'minor' originalDraftHash.value = getDraftHash()
form.version = versionOptions.value.minor
// 6. 弹窗状态机:标题"新增 BOM"父件可改启用版本升级单选 dialogTitle.value = '新增 BOM (版本升级)'
dialogTitle.value = '新增 BOM'
isEditMode.value = false isEditMode.value = false
isSaveAsMode.value = true isSaveAsMode.value = true
isReadOnlyMode.value = false isReadOnlyMode.value = false
@ -844,6 +863,7 @@ const submitForm = async () => {
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('发布成功') ElMessage.success('发布成功')
localStorage.removeItem('pending_bom_draft_no') localStorage.removeItem('pending_bom_draft_no')
localStorage.removeItem('pending_bom_draft_version')
originalDraftHash.value = '' originalDraftHash.value = ''
dialogVisible.value = false dialogVisible.value = false
fetchBomList() fetchBomList()