This commit is contained in:
zlwu committed 2026-08-26 11:10:40 +08:00
1 parent dd1acdc787
commit 4222eaa593
47 files changed
+1054350 -9663

No files matched your search

+69 -19
View File
@@ -102,6 +102,27 @@
:selected-ids="selectedRows.map((r) => r.id)"
filename="计划归档.xlsx"
/>
<el-dropdown trigger="click" @command="handleBatchErpCommand">
<el-button
class="btn-ghost"
:disabled="selectedRows.length === 0"
:loading="erpBatchLoading"
>
<el-icon><DocumentChecked /></el-icon>
ERP录入
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="entered" :disabled="erpBatchLoading">
已录入ERP
</el-dropdown-item>
<el-dropdown-item command="not_entered" :disabled="erpBatchLoading">
未录入ERP
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<ListToolbarEndActions
:loading="loading"
@@ -229,10 +250,8 @@
<template #default="{ row }">
<div class="pl-plan-archive-erp-cell" @click.stop @mousedown.stop>
<el-checkbox
class="pl-plan-archive-erp-checkbox"
:model-value="Number(row.erpEntered) === 1"
:disabled="row.followStatus === 'cancelled' || erpUpdatingId === row.id"
@click.stop
@change="(checked) => handleErpEnteredChange(row, Boolean(checked))"
/>
</div>
</template>
@@ -431,6 +450,8 @@ import ListColumnStatsRow from '@/components/business/list-column-stats-row/inde
import type { StatsRowColumn } from '@/utils/list-column-stats'
import { usePersistedListColumns } from '@/composables/usePersistedListColumns'
import {
ArrowDown,
DocumentChecked,
FolderChecked,
RefreshLeft,
Search
@@ -472,7 +493,7 @@ const viewPlanId = ref('')
const viewDialogRef = ref<InstanceType<typeof PlPlanViewDialog>>()
const archiveDialogVisible = ref(false)
const archivePlanId = ref('')
const erpUpdatingId = ref('')
const erpBatchLoading = ref(false)
const planList = ref<Plan[]>([])
const listColumnDefs = [
@@ -765,25 +786,49 @@ function handleToolbarArchive() {
handleArchive(selectedRows.value[0])
}
async function handleErpEnteredChange(row: Plan, entered: boolean) {
if (row.followStatus === 'cancelled') return
const previous = Number(row.erpEntered) === 1
if (previous === entered) return
async function handleBatchErpCommand(command: 'entered' | 'not_entered') {
const entered = command === 'entered'
const eligibleRows = selectedRows.value.filter((row) => row.followStatus !== 'cancelled')
if (eligibleRows.length === 0) {
ElMessage.warning('请选择未作废的计划')
return
}
erpUpdatingId.value = row.id
row.erpEntered = entered ? 1 : 0
const targets = eligibleRows.filter((row) => (Number(row.erpEntered) === 1) !== entered)
if (targets.length === 0) {
ElMessage.info(entered ? '所选计划均已录入 ERP' : '所选计划均未录入 ERP')
return
}
erpBatchLoading.value = true
try {
const res = await planApi.setErpEntered(row.id, entered)
const data = pickBxData<Plan>(res)
if (data?.id) {
row.erpEntered = data.erpEntered ?? (entered ? 1 : 0)
const results = await Promise.allSettled(
targets.map((row) => planApi.setErpEntered(row.id, entered))
)
let successCount = 0
results.forEach((result, index) => {
const row = targets[index]
if (result.status === 'fulfilled') {
const data = pickBxData<Plan>(result.value)
row.erpEntered = data?.erpEntered ?? (entered ? 1 : 0)
successCount += 1
return
}
const message =
result.reason instanceof Error ? result.reason.message : '更新 ERP 状态失败'
ElMessage.error(
`${row.planNo || row.id}:${message.includes('失败') ? message : `更新 ERP 状态失败:${message}`}`
)
})
if (successCount > 0) {
ElMessage.success(
entered ? `已将 ${successCount} 条计划标记为已录入 ERP` : `已将 ${successCount} 条计划标记为未录入 ERP`
)
await refreshViewIfOpen()
}
} catch (error) {
row.erpEntered = previous ? 1 : 0
const message = error instanceof Error ? error.message : '更新 ERP 状态失败'
ElMessage.error(message.includes('失败') ? message : `更新 ERP 状态失败:${message}`)
} finally {
erpUpdatingId.value = ''
erpBatchLoading.value = false
}
}
@@ -822,4 +867,9 @@ onMounted(() => {
align-items: center;
justify-content: center;
}
.pl-plan-archive-erp-checkbox {
pointer-events: none;
cursor: default;
}
</style>
+23 -23
View File
@@ -173,15 +173,6 @@
>
<el-icon><DocumentCopy /></el-icon>三方人车快速创建
</el-button>
<el-button
v-if="canForceFollowStatus"
class="btn-ghost"
:disabled="!selectedPlan"
@click="openForceFollowStatusDialog"
>
<el-icon><EditPen /></el-icon>强制改状态
</el-button>
<ListExportDropdown
:export-fn="planApi.export"
:get-filter-params="getPlanExportFilterParams"
@@ -571,6 +562,13 @@
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button
v-if="canForceFollowStatus"
class="btn-ghost"
@click="openForceFollowStatusDialog"
>
<el-icon><EditPen /></el-icon>强制改状态
</el-button>
<el-button
v-if="canVoidPlan(viewingPlan)"
class="btn-ghost"
@@ -614,27 +612,27 @@
>
<el-form label-position="top" class="form-grid-2">
<el-form-item label="计划编号" style="margin-bottom: 0">
<span>{{ selectedPlan?.planNo || '—' }}</span>
<span>{{ viewingPlan?.planNo || '—' }}</span>
</el-form-item>
<el-form-item label="单据类型" style="margin-bottom: 0">
<span>{{ getPlanTypeLabel(selectedPlan?.planType) }}</span>
<span>{{ getPlanTypeLabel(viewingPlan?.planType) }}</span>
</el-form-item>
<el-form-item label="供方" style="margin-bottom: 0">
<span>{{ selectedPlan?.supplierName || '—' }}</span>
<span>{{ viewingPlan?.supplierName || '—' }}</span>
</el-form-item>
<el-form-item label="需方" style="margin-bottom: 0">
<span>{{ selectedPlan?.customerName || '—' }}</span>
<span>{{ viewingPlan?.customerName || '—' }}</span>
</el-form-item>
<el-form-item label="产品信息" class="form-col-span-2" style="margin-bottom: 0">
<PlPlanListProductCell :products="selectedPlan?.products || []" />
<PlPlanListProductCell :products="viewingPlan?.products || []" />
</el-form-item>
<el-form-item label="当前跟进状态" style="margin-bottom: 0">
<el-tag
v-if="selectedPlan"
:type="getPlPlanFollowStatusTagType(selectedPlan.followStatus)"
v-if="viewingPlan"
:type="getPlPlanFollowStatusTagType(viewingPlan.followStatus)"
size="small"
>
{{ getPlPlanFollowStatusLabel(selectedPlan.followStatus) }}
{{ getPlPlanFollowStatusLabel(viewingPlan.followStatus) }}
</el-tag>
<span v-else>—</span>
</el-form-item>
@@ -1284,8 +1282,8 @@ function handleToolbarVoid() {
}
function openForceFollowStatusDialog() {
if (!selectedPlan.value) return
forceFollowStatusValue.value = selectedPlan.value.followStatus || ''
if (!viewingPlan.value) return
forceFollowStatusValue.value = viewingPlan.value.followStatus || ''
forceFollowDialogVisible.value = true
}
@@ -1294,22 +1292,24 @@ function resetForceFollowDialog() {
}
async function submitForceFollowStatus() {
if (!selectedPlan.value) return
if (!viewingPlan.value) return
const next = (forceFollowStatusValue.value || '').trim()
if (!next) {
ElMessage.warning('请选择目标跟进状态')
return
}
if (next === selectedPlan.value.followStatus) {
if (next === viewingPlan.value.followStatus) {
ElMessage.warning('目标状态与当前状态相同')
return
}
forceFollowLoading.value = true
try {
await planApi.forceFollowStatus(selectedPlan.value.id, next)
await planApi.forceFollowStatus(viewingPlan.value.id, next)
ElMessage.success('跟进状态已更新')
forceFollowDialogVisible.value = false
fetchData()
syncViewingPlan({ ...viewingPlan.value, followStatus: next })
await fetchData()
await refreshViewIfOpen()
} catch (e) {
const message = e instanceof Error ? e.message : '修改失败'
ElMessage.error(message)