diff --git a/web-admin/src/api/pl/index.ts b/web-admin/src/api/pl/index.ts
index 60f50551b..f0be669c6 100644
--- a/web-admin/src/api/pl/index.ts
+++ b/web-admin/src/api/pl/index.ts
@@ -691,6 +691,7 @@ export interface PlanCreateFullPayload {
followUserId?: string
followUserName?: string
remark?: string
+ saveMode?: 'draft' | 'formal'
supplierContracts?: PlanContractLink[]
demanderContracts?: PlanContractLink[]
load?: PlanLoad
diff --git a/web-admin/src/components/business/pl-plan-form-dialog/index.vue b/web-admin/src/components/business/pl-plan-form-dialog/index.vue
index 92c7e6b73..f8cb01ebc 100644
--- a/web-admin/src/components/business/pl-plan-form-dialog/index.vue
+++ b/web-admin/src/components/business/pl-plan-form-dialog/index.vue
@@ -254,6 +254,13 @@
取消
+
+ 暂存
+
(createEmptyLoadForm())
const deliveryForms = ref([createEmptyDeliveryForm(1)])
const loadedPlanSnapshot = ref(null)
@@ -489,6 +498,12 @@
/** 已安排:禁止仅「保存」,须走保存并安排/调整运输,避免计划与地磅等联动字段脱节 */
const showSaveButton = computed(() => loadedTransportStatus.value !== 'arranged')
+ const showDraftButton = computed(() => {
+ if (!isEdit.value) return true
+ return (
+ loadedFollowStatus.value === 'drafting' || loadedFollowStatus.value === 'pending_arrange'
+ )
+ })
const showSaveAndArrangeButton = computed(() => {
if (!isEdit.value) return true
if (props.openForArrange && loadedTransportStatus.value === 'arranged') return false
@@ -1577,6 +1592,7 @@
function resetForm() {
loadedTransportStatus.value = 'pending'
+ loadedFollowStatus.value = ''
loadedPlanSnapshot.value = null
vehicleBundle.value = null
selectedDriverId.value = ''
@@ -1669,6 +1685,7 @@
})
applyStopsFromPlan(data)
loadedTransportStatus.value = data.transportStatus || 'pending'
+ loadedFollowStatus.value = data.followStatus || ''
loadedPlanSnapshot.value = data
syncCommittedPartyIds()
@@ -1731,6 +1748,7 @@
products: row.products.map((product) => ({ ...product, planProductId: undefined }))
}))
loadedTransportStatus.value = 'pending'
+ loadedFollowStatus.value = ''
syncCommittedPartyIds()
formData.products = await enrichPlanProductLinesAlias(
@@ -1976,11 +1994,51 @@
return missing
}
- async function handleSubmit(mode: 'save' | 'saveAndArrange' | 'rearrange' = 'save') {
+ async function handleSubmit(
+ mode: 'draft' | 'save' | 'saveAndArrange' | 'rearrange' = 'save'
+ ) {
// 必须在 await validate 之前置位,避免连点并发多次 createFull
if (submitLoading.value) return
submitLoading.value = true
try {
+ if (mode === 'draft') {
+ const companyOk = !!(formData.belongsCompany || '').trim()
+ const dateOk = !!(formData.createDate || '').trim()
+ if (!companyOk || !dateOk) {
+ ElMessage.warning('暂存请至少填写归属公司和创建日期')
+ await basicFormRef.value
+ ?.validateField?.(['belongsCompany', 'createDate'])
+ .catch(() => undefined)
+ return
+ }
+ mirrorPlanProductsFromLoad()
+ const draftPayload = {
+ ...buildPlanCommonPayload({ allowClearTransport: isEdit.value }),
+ saveMode: 'draft' as const,
+ hasFreight: formData.hasFreight
+ }
+ let planId = props.planId || ''
+ if (isEdit.value) {
+ if (!props.planId) return
+ await planApi.update(props.planId, draftPayload)
+ planId = props.planId
+ } else {
+ const res = await planApi.createFull(
+ draftPayload as Parameters[0]
+ )
+ const created = pickBxData(res)
+ planId = String(created?.id || '')
+ if (!planId) {
+ ElMessage.error('暂存成功但未返回计划 ID')
+ return
+ }
+ }
+ ElMessage.success('暂存成功')
+ innerVisible.value = false
+ emit('success', { planId, arranged: false })
+ return
+ }
+
const valid = await basicFormRef.value?.validate().catch(() => false)
if (!valid || !validateBusinessRules()) return
if (!validateSingleContractPerStop()) return
@@ -2000,7 +2058,10 @@
}
mirrorPlanProductsFromLoad()
- const commonPayload = buildPlanCommonPayload({ allowClearTransport: isEdit.value })
+ const commonPayload = {
+ ...buildPlanCommonPayload({ allowClearTransport: isEdit.value }),
+ saveMode: 'formal' as const
+ }
let planId = props.planId || ''
const wasCreate = !isEdit.value
diff --git a/web-admin/src/utils/pl-display.ts b/web-admin/src/utils/pl-display.ts
index c8f8e80d2..ed57668f9 100644
--- a/web-admin/src/utils/pl-display.ts
+++ b/web-admin/src/utils/pl-display.ts
@@ -366,7 +366,7 @@ export const PL_PLAN_TYPE_TABS: { label: string; name: PlPlanTypeTab }[] = [
]
export const PL_PLAN_LIST_TABS: { label: string; name: PlPlanListTab }[] = [
- { label: '待安排', name: 'pending_arrange' },
+ { label: '待安排/草稿', name: 'pending_arrange' }, // name 保留;语义含 drafting
...PL_PLAN_TYPE_TABS
]
@@ -384,7 +384,8 @@ export function plPlanListTabToFilters(tab: PlPlanListTab): {
followStatus?: string
} {
if (tab === 'pending_arrange') {
- return { planType: '', followStatus: 'pending_arrange' }
+ // followStatus 由列表 searchForm 控制(默认 pending_arrange + drafting)
+ return { planType: '' }
}
return { planType: plPlanTypeTabToFilter(tab) }
}
@@ -419,6 +420,7 @@ export function plPlanTypeFilterToTab(planType?: string): PlPlanTypeTab {
/** 运输计划跟进状态选项(筛选) */
export const PL_PLAN_FOLLOW_STATUS_OPTIONS = [
+ { label: '草稿中', value: 'drafting' },
{ label: '等通知', value: 'wait_notice' },
{ label: '待安排', value: 'pending_arrange' },
{ label: '已安排', value: 'arranged' },
@@ -433,6 +435,7 @@ export const PL_PLAN_DEFAULT_FOLLOW_STATUSES = PL_PLAN_FOLLOW_STATUS_OPTIONS.fil
export function getPlPlanFollowStatusTagType(status?: string) {
const map: Record = {
+ drafting: 'info',
wait_notice: 'warning',
pending_arrange: 'danger',
arranged: 'success',
@@ -447,6 +450,7 @@ export function getPlPlanFollowStatusTagType(status?: string) {
export function getPlPlanFollowStatusLabel(status?: string) {
const map: Record = {
+ drafting: '草稿中',
wait_notice: '等通知',
pending_arrange: '待安排',
arranged: '已安排',
diff --git a/web-admin/src/views/pl/plan/index.vue b/web-admin/src/views/pl/plan/index.vue
index c61dfc3a8..ad5570d24 100644
--- a/web-admin/src/views/pl/plan/index.vue
+++ b/web-admin/src/views/pl/plan/index.vue
@@ -26,7 +26,6 @@
placeholder="全部"
clearable
multiple
- :disabled="activePlanTypeTab === 'pending_arrange'"
>