提交
This commit is contained in:
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)
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user