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

@@ -125,6 +125,7 @@
hide-nav
:tab="viewTab"
show-archive-io-fields
show-actual-qty-disclaimer
feedback-editable
:arrange-driver-url="driverUrl"
:arrange-site-records="siteRecords"
@@ -211,7 +212,7 @@
const productRows = ref<PlanFormProductRow[]>([])
const formData = reactive({
hasFreight: 0,
hasFreight: 1,
distanceKm: null as number | null,
freightType: 'by_weight'
})
@@ -413,7 +414,7 @@
plan.value = {}
productRows.value = []
Object.assign(formData, {
hasFreight: 0,
hasFreight: 1,
distanceKm: null,
freightType: 'by_weight'
})
@@ -422,7 +423,7 @@
}
async function applyFreightPrefill(data: Plan) {
formData.hasFreight = data.hasFreight ?? 0
formData.hasFreight = isAdjustMode.value ? (data.hasFreight ?? 0) : 1
freightCalc.resetFreightCalc()
if (data.freightAmount != null && data.hasFreight === 1) {
@@ -25,6 +25,7 @@
type="date"
placeholder="选择日期"
value-format="YYYY-MM-DD"
:disabled="!isEdit"
style="width: 100%"
/>
</el-form-item>
@@ -589,7 +590,11 @@ function resolveCurrentUserName() {
}
function todayYmd(): string {
return new Date().toISOString().split('T')[0]
const d = new Date()
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
const isEdit = computed(() => !!props.planId)
@@ -24,10 +24,12 @@
displayFeedbackTime || '—'
}}</span>
</div>
<p v-if="!hasDriverFeedback" class="pl-plan-form-empty-hint pl-feedback-ticket-empty"
<p
v-if="!hasDriverFeedback && !driverImagesEditable"
class="pl-plan-form-empty-hint pl-feedback-ticket-empty"
>暂无司机回传</p
>
<template v-else>
<template v-if="hasDriverFeedback">
<div
v-for="row in driverTicketQtyRows"
:key="row.key"
@@ -40,6 +42,9 @@
<div>
<div class="pl-feedback-ticket-lab">实际数量({{ feedbackQtyUnit }})</div>
<div class="pl-feedback-ticket-val">{{ row.actualQty }}</div>
<div v-if="showActualQtyDisclaimer" class="pl-feedback-ticket-val-tip"
>(仅供参考,实际以附件中数量为准)</div
>
</div>
<div>
<div class="pl-feedback-ticket-lab">品牌数量</div>
@@ -55,18 +60,23 @@
<span class="pl-feedback-ticket-text">{{ feedbackRemark || '—' }}</span>
</div>
</div>
<div class="pl-feedback-ticket-foot">
<span class="pl-feedback-ticket-lab">附件</span>
<AttachmentUploadField
v-if="feedbackImageCsv"
class="pl-feedback-ticket-attach"
:model-value="feedbackImageCsv"
compact
disabled
/>
<span v-else class="pl-plan-form-empty-hint">—</span>
</div>
</template>
<div class="pl-feedback-ticket-foot">
<span class="pl-feedback-ticket-lab">附件</span>
<AttachmentUploadField
v-if="driverImagesEditable || feedbackImageCsv"
class="pl-feedback-ticket-attach"
:class="{ 'pl-feedback-ticket-attach--editable': driverImagesEditable }"
:model-value="feedbackImageCsv"
:disabled="!driverImagesEditable"
compact
folder="pl/transport/feedback"
accept="image/*,video/*,.pdf"
:limit="15"
@update:model-value="handleDriverImagesChange"
/>
<span v-else class="pl-plan-form-empty-hint">—</span>
</div>
</div>
</div>
<div v-if="feedbackEditable" class="pl-plan-feedback-card-footer">
@@ -106,6 +116,9 @@
<div>
<div class="pl-feedback-ticket-lab">实际数量({{ feedbackQtyUnit }})</div>
<div class="pl-feedback-ticket-val">{{ row.actualQty }}</div>
<div v-if="showActualQtyDisclaimer" class="pl-feedback-ticket-val-tip"
>(仅供参考,实际以附件中数量为准)</div
>
</div>
<div>
<div class="pl-feedback-ticket-lab">品牌数量</div>
@@ -148,11 +161,16 @@
<div class="pl-feedback-ticket-foot">
<span class="pl-feedback-ticket-lab">附件</span>
<AttachmentUploadField
v-if="ioOrderImageCsv"
v-if="ioOrderImagesEditable || ioOrderImageCsv"
class="pl-feedback-ticket-attach"
:class="{ 'pl-feedback-ticket-attach--editable': ioOrderImagesEditable }"
:model-value="ioOrderImageCsv"
:disabled="!ioOrderImagesEditable"
compact
disabled
folder="pl/transport/site-feedback"
accept="image/*,video/*,.pdf"
:limit="15"
@update:model-value="handleIoOrderImagesChange"
/>
<span v-else class="pl-plan-form-empty-hint">—</span>
</div>
@@ -386,8 +404,12 @@
feedbackEditable?: boolean
/** 仅运输计划归档:展示入库/出库单价与金额 */
showArchiveIoFields?: boolean
/** 司机/出库单回传「实际数量」后展示仅供参考说明 */
showActualQtyDisclaimer?: boolean
loading?: boolean
canEditDriverFeedback?: boolean
driverImagesEditable?: boolean
ioOrderImagesEditable?: boolean
hasDriverFeedback?: boolean
arrangeDriverUrl?: string
driverFeedbackTableRows?: DriverFeedbackTableRow[]
@@ -407,8 +429,11 @@
{
feedbackEditable: false,
showArchiveIoFields: false,
showActualQtyDisclaimer: false,
loading: false,
canEditDriverFeedback: false,
driverImagesEditable: false,
ioOrderImagesEditable: false,
hasDriverFeedback: false,
arrangeDriverUrl: '',
driverFeedbackTableRows: () => [],
@@ -532,8 +557,20 @@
'copy-site-url': [url?: string]
'edit-site-feedback': [row: SiteFeedbackTableRow]
'copy-site-summary': [row: SiteFeedbackTableRow]
'save-driver-images': [csv: string]
'save-io-order-images': [csv: string]
}>()
function handleDriverImagesChange(csv: string) {
if (!props.driverImagesEditable) return
emit('save-driver-images', csv)
}
function handleIoOrderImagesChange(csv: string) {
if (!props.ioOrderImagesEditable) return
emit('save-io-order-images', csv)
}
const ioSectionTitle = computed(() => {
if (!props.ioOrder) return '现场回传信息'
return props.ioOrder.kind === 'inbound' ? '入库单回传' : '出库单回传'
@@ -824,6 +861,22 @@
}
}
/* 可编辑:沿用紧凑上传卡片尺寸,与只读缩略图同排展示 */
.pl-feedback-ticket-attach--editable {
:deep(.attachment-item) {
width: 88px;
}
:deep(.attachment-preview) {
height: 66px;
}
:deep(.attachment-preview__icon) {
width: 36px;
min-height: 36px;
}
}
.pl-feedback-ticket-band {
display: flex;
align-items: center;
@@ -875,6 +928,14 @@
margin-bottom: 4px;
}
.pl-feedback-ticket-val-tip {
margin-top: 4px;
font-size: 11px;
line-height: 1.4;
font-weight: 400;
color: var(--mint-text-muted, #94a3b8);
}
.pl-feedback-ticket-val {
font-size: 22px;
font-weight: 700;
@@ -392,6 +392,7 @@
import {
inboundOrderApi,
outboundOrderApi,
planApi,
type PlIoOrder,
type TransportSiteLink
} from '@/api/pl'
@@ -440,6 +441,8 @@
tab?: string
/** 仅运输计划归档:展示入库/出库单价与金额 */
showArchiveIoFields?: boolean
/** 司机/出库单回传「实际数量」后展示仅供参考说明 */
showActualQtyDisclaimer?: boolean
/** 计划概况产品表:展示入库/出库数量(不含单价与金额) */
showInboundOutboundQty?: boolean
}>(),
@@ -453,6 +456,7 @@
hideNav: false,
tab: undefined,
showArchiveIoFields: false,
showActualQtyDisclaimer: false,
showInboundOutboundQty: false
}
)
@@ -580,6 +584,8 @@
const ioOrderEditVisible = ref(false)
const ioOrderSaving = ref(false)
const driverImagesSaving = ref(false)
const ioOrderImagesSaving = ref(false)
const ioOrderEditForm = ref<PlIoOrder | null>(null)
const ioOrderEditImagesCsv = ref('')
@@ -1092,6 +1098,60 @@
reload()
}
async function saveDriverImagesInline(csv: string) {
if (!props.planId || driverImagesSaving.value) return
const nextList = csv
? csv
.split(',')
.map((item) => item.trim())
.filter(Boolean)
: []
if (nextList.join(',') === feedbackImageList.value.join(',')) return
driverImagesSaving.value = true
try {
await planApi.updateDriverFeedback(props.planId, {
feedbackImages: nextList
})
ElMessage.success('司机回传附件已保存')
reload()
} catch (e) {
ElMessage.error(e instanceof Error ? e.message : '保存失败')
} finally {
driverImagesSaving.value = false
}
}
async function saveIoOrderImagesInline(csv: string) {
const order = ioOrder.value
if (!order || ioOrderImagesSaving.value || order.status === 'voided') return
const nextList = csv
? csv
.split(',')
.map((item) => item.trim())
.filter(Boolean)
: []
const currentList = Array.isArray(order.siteFeedbackImages)
? order.siteFeedbackImages.filter(Boolean)
: []
if (nextList.join(',') === currentList.join(',')) return
const api = order.kind === 'inbound' ? inboundOrderApi : outboundOrderApi
const label = order.kind === 'inbound' ? '入库单' : '出库单'
ioOrderImagesSaving.value = true
try {
await api.patch(order.id, {
siteFeedbackImages: nextList
})
ElMessage.success(`${label}回传附件已保存`)
reload()
} catch (e) {
ElMessage.error(e instanceof Error ? e.message : '保存失败')
} finally {
ioOrderImagesSaving.value = false
}
}
const hasArrangeSiteLinks = computed(
() => props.showArrangeLinks && (props.arrangeSiteRecords?.length ?? 0) > 0
)
@@ -1149,8 +1209,13 @@
const feedbackBlocksBind = computed(() => ({
feedbackEditable: props.feedbackEditable,
showArchiveIoFields: props.showArchiveIoFields,
showActualQtyDisclaimer: props.showActualQtyDisclaimer,
loading: loading.value,
canEditDriverFeedback: canEditDriverFeedback.value,
driverImagesEditable: props.feedbackEditable && canEditDriverFeedback.value,
ioOrderImagesEditable: Boolean(
props.feedbackEditable && ioOrder.value && ioOrder.value.status !== 'voided'
),
hasDriverFeedback: hasDriverFeedback.value,
arrangeDriverUrl: props.arrangeDriverUrl,
driverFeedbackTableRows: driverFeedbackTableRows.value,
@@ -1172,6 +1237,12 @@
'edit-driver': openDriverFeedbackDialog,
'copy-driver-url': copyArrangeDriverUrl,
'edit-io-order': openIoOrderEditDialog,
'save-driver-images': (csv: string) => {
void saveDriverImagesInline(csv)
},
'save-io-order-images': (csv: string) => {
void saveIoOrderImagesInline(csv)
},
'copy-site-url': (url?: string) => {
void copyArrangeSiteUrl(url)
},