|
|
@@ -171,81 +171,102 @@
|
|
|
</div>
|
|
|
|
|
|
<div class="pl-plan-feedback-region">
|
|
|
- <h4 class="pl-plan-feedback-region__title">现场回传信息</h4>
|
|
|
- <p v-if="!siteInventoryRows.length && !loading" class="pl-plan-form-empty-hint">
|
|
|
- 暂无现场链接
|
|
|
- </p>
|
|
|
- <div v-else class="view-subtable-wrap">
|
|
|
- <el-table :data="siteFeedbackTableRows" class="view-subtable list-table" stripe>
|
|
|
- <el-table-column
|
|
|
- type="index"
|
|
|
- label="序号"
|
|
|
- min-width="68"
|
|
|
- align="center"
|
|
|
- header-align="center"
|
|
|
- />
|
|
|
- <el-table-column
|
|
|
- prop="productName"
|
|
|
- label="产品"
|
|
|
- min-width="140"
|
|
|
- show-overflow-tooltip
|
|
|
- />
|
|
|
- <el-table-column
|
|
|
- prop="siteFeedbackTime"
|
|
|
- label="保存时间"
|
|
|
- min-width="160"
|
|
|
- align="center"
|
|
|
- />
|
|
|
- <el-table-column label="业务类型" min-width="100" align="center">
|
|
|
- <template #default="{ row }">
|
|
|
- <el-tag
|
|
|
- v-if="row.businessType && row.businessType !== '—'"
|
|
|
- :type="businessTypeTagType(row.businessType)"
|
|
|
- size="small"
|
|
|
- >
|
|
|
- {{ row.businessType }}
|
|
|
- </el-tag>
|
|
|
- <span v-else class="pl-plan-feedback-table__empty-cell">—</span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column
|
|
|
- prop="siteFeedbackRemark"
|
|
|
- label="现场备注"
|
|
|
- min-width="160"
|
|
|
- show-overflow-tooltip
|
|
|
+ <h4 class="pl-plan-feedback-region__title">
|
|
|
+ {{ ioOrder ? (ioOrder.kind === 'inbound' ? '入库单回传' : '出库单回传') : '现场回传信息' }}
|
|
|
+ </h4>
|
|
|
+ <!-- 新链路:入库/出库单权威展示 -->
|
|
|
+ <template v-if="ioOrder">
|
|
|
+ <ViewKvTable :fields="ioOrderViewFields" mode="quint" />
|
|
|
+ <div class="view-subtable-wrap" style="margin-top: 12px">
|
|
|
+ <el-table :data="ioOrder.items || []" class="view-subtable list-table" stripe>
|
|
|
+ <el-table-column type="index" label="序号" min-width="68" align="center" />
|
|
|
+ <el-table-column prop="productNo" label="产品编号" min-width="110" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="productName" label="产品名称" min-width="120" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="specification" label="型号/规格" min-width="100" show-overflow-tooltip />
|
|
|
+ <el-table-column label="单位" min-width="72" align="center">
|
|
|
+ <template #default="{ row }">{{ row.unitLabel || row.unit || '—' }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="planQty" label="计划数量" min-width="100" align="right" />
|
|
|
+ <el-table-column prop="actualQty" label="实际数量" min-width="100" align="right" />
|
|
|
+ <el-table-column prop="packageSpec" label="包装规格" min-width="110" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="remark" label="备注" min-width="120" show-overflow-tooltip />
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <div style="margin-top: 12px">
|
|
|
+ <p class="pl-plan-form-empty-hint" style="margin-bottom: 6px">现场备注</p>
|
|
|
+ <p class="pl-plan-view-remark">{{ ioOrder.siteFeedbackRemark || '—' }}</p>
|
|
|
+ </div>
|
|
|
+ <div style="margin-top: 12px">
|
|
|
+ <p class="pl-plan-form-empty-hint" style="margin-bottom: 6px">现场附件</p>
|
|
|
+ <AttachmentUploadField
|
|
|
+ v-if="ioOrderImageCsv"
|
|
|
+ :model-value="ioOrderImageCsv"
|
|
|
+ disabled
|
|
|
+ compact
|
|
|
/>
|
|
|
- <el-table-column label="现场附件" min-width="140" align="center" header-align="center">
|
|
|
- <template #default="{ row }">
|
|
|
- <div v-if="row.siteFeedbackImages" class="pl-plan-feedback-table__attachment">
|
|
|
- <AttachmentUploadField :model-value="row.siteFeedbackImages" disabled compact />
|
|
|
- </div>
|
|
|
- <span v-else class="pl-plan-feedback-table__empty-cell">—</span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column
|
|
|
- label="操作"
|
|
|
- min-width="240"
|
|
|
- align="center"
|
|
|
- fixed="right"
|
|
|
- class-name="col-actions"
|
|
|
- >
|
|
|
- <template #default="{ row }">
|
|
|
- <el-button
|
|
|
- v-if="feedbackEditable"
|
|
|
- class="btn-op-item"
|
|
|
- @click="openSiteFeedbackDialog(row)"
|
|
|
- >
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- {{ rowHasSiteFeedback(row) ? '编辑' : '补充' }}
|
|
|
- </el-button>
|
|
|
- <el-button class="btn-op-item" @click="copySiteSummaryForRow(row.sourceRow)">
|
|
|
- <el-icon><CopyDocument /></el-icon>
|
|
|
- 复制给现场
|
|
|
- </el-button>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </div>
|
|
|
+ <span v-else class="pl-plan-feedback-table__empty-cell">—</span>
|
|
|
+ </div>
|
|
|
+ <div style="margin-top: 12px; display: flex; gap: 8px">
|
|
|
+ <el-button v-if="feedbackEditable && ioOrder.status !== 'voided'" @click="openIoOrderEditDialog">
|
|
|
+ <el-icon><Edit /></el-icon>
|
|
|
+ {{ ioOrderHasFeedback ? '编辑' : '补充' }}
|
|
|
+ </el-button>
|
|
|
+ <el-button v-if="ioOrder.siteUrl" @click="copyArrangeSiteUrl(ioOrder.siteUrl)">
|
|
|
+ <el-icon><CopyDocument /></el-icon>
|
|
|
+ 复制现场链接
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <!-- 旧链路:按产品现场 link -->
|
|
|
+ <template v-else>
|
|
|
+ <p v-if="!siteInventoryRows.length && !loading" class="pl-plan-form-empty-hint">
|
|
|
+ 暂无现场链接
|
|
|
+ </p>
|
|
|
+ <div v-else class="view-subtable-wrap">
|
|
|
+ <el-table :data="siteFeedbackTableRows" class="view-subtable list-table" stripe>
|
|
|
+ <el-table-column type="index" label="序号" min-width="68" align="center" />
|
|
|
+ <el-table-column prop="productName" label="产品" min-width="140" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="siteFeedbackTime" label="保存时间" min-width="160" align="center" />
|
|
|
+ <el-table-column label="业务类型" min-width="100" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-tag
|
|
|
+ v-if="row.businessType && row.businessType !== '—'"
|
|
|
+ :type="businessTypeTagType(row.businessType)"
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ {{ row.businessType }}
|
|
|
+ </el-tag>
|
|
|
+ <span v-else class="pl-plan-feedback-table__empty-cell">—</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="siteFeedbackRemark" label="现场备注" min-width="160" show-overflow-tooltip />
|
|
|
+ <el-table-column label="现场附件" min-width="140" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div v-if="row.siteFeedbackImages" class="pl-plan-feedback-table__attachment">
|
|
|
+ <AttachmentUploadField :model-value="row.siteFeedbackImages" disabled compact />
|
|
|
+ </div>
|
|
|
+ <span v-else class="pl-plan-feedback-table__empty-cell">—</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" min-width="240" align="center" fixed="right">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button
|
|
|
+ v-if="feedbackEditable"
|
|
|
+ class="btn-op-item"
|
|
|
+ @click="openSiteFeedbackDialog(row)"
|
|
|
+ >
|
|
|
+ <el-icon><Edit /></el-icon>
|
|
|
+ {{ rowHasSiteFeedback(row) ? '编辑' : '补充' }}
|
|
|
+ </el-button>
|
|
|
+ <el-button class="btn-op-item" @click="copySiteSummaryForRow(row.sourceRow)">
|
|
|
+ <el-icon><CopyDocument /></el-icon>
|
|
|
+ 复制给现场
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
|
|
|
<h4 class="pl-plan-subtitle">地磅单信息</h4>
|
|
|
@@ -455,6 +476,46 @@
|
|
|
:site-feedback-time="siteFeedbackTarget.siteFeedbackTime"
|
|
|
@success="handleFeedbackSaved"
|
|
|
/>
|
|
|
+ <el-dialog
|
|
|
+ v-model="ioOrderEditVisible"
|
|
|
+ :title="ioOrder?.kind === 'inbound' ? '编辑入库单回传' : '编辑出库单回传'"
|
|
|
+ width="1080px"
|
|
|
+ align-center
|
|
|
+ destroy-on-close
|
|
|
+ class="dialog-form-layout"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <el-form v-if="ioOrderEditForm" label-position="top">
|
|
|
+ <el-form-item label="产品实际数量">
|
|
|
+ <el-table :data="ioOrderEditForm.items || []" size="small" border>
|
|
|
+ <el-table-column prop="productNo" label="产品编号" min-width="110" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="productName" label="产品名称" min-width="120" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="specification" label="型号/规格" min-width="100" show-overflow-tooltip />
|
|
|
+ <el-table-column label="单位" min-width="72" align="center">
|
|
|
+ <template #default="{ row }">{{ row.unitLabel || row.unit || '—' }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="planQty" label="计划数量" min-width="100" align="right" />
|
|
|
+ <el-table-column label="实际数量" min-width="120">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-input-number v-model="row.actualQty" :min="0" :precision="3" :controls="false" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="packageSpec" label="包装规格" min-width="110" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="remark" label="备注" min-width="120" show-overflow-tooltip />
|
|
|
+ </el-table>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="现场备注">
|
|
|
+ <el-input v-model="ioOrderEditForm.siteFeedbackRemark" type="textarea" :rows="3" maxlength="500" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="现场附件">
|
|
|
+ <AttachmentUploadField v-model="ioOrderEditImagesCsv" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="ioOrderEditVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" :loading="ioOrderSaving" @click="saveIoOrderEdit">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
<PlVehicleViewDialog
|
|
|
v-model:visible="vehicleViewVisible"
|
|
|
:vehicle-id="plan?.vehicleId"
|
|
|
@@ -480,7 +541,12 @@
|
|
|
} from '@/components/business/db/db-related-view'
|
|
|
import type { ContractVO } from '@/api/crm/contract/types'
|
|
|
import { inventoryApi } from '@/api/db/inventory'
|
|
|
- import type { TransportSiteLink } from '@/api/pl'
|
|
|
+ import {
|
|
|
+ inboundOrderApi,
|
|
|
+ outboundOrderApi,
|
|
|
+ type PlIoOrder,
|
|
|
+ type TransportSiteLink
|
|
|
+ } from '@/api/pl'
|
|
|
import { mapContractProducts, type PlanFormProductRow } from '@/composables/usePlContractToPlan'
|
|
|
import { mapPlanProductToFormRow, usePlPlanViewDetail, type PlPlanTransportDibangRow, type PlPlanTransportSiteRow } from '@/composables/usePlPlanViewDetail'
|
|
|
import { resolveFreightUnitLabel } from '@/composables/usePlFreightCalc'
|
|
|
@@ -551,10 +617,102 @@
|
|
|
contractSnapshot,
|
|
|
dibangRows,
|
|
|
siteRows,
|
|
|
+ ioOrder,
|
|
|
loadDetail,
|
|
|
resetDetail
|
|
|
} = usePlPlanViewDetail()
|
|
|
|
|
|
+ const ioOrderEditVisible = ref(false)
|
|
|
+ const ioOrderSaving = ref(false)
|
|
|
+ const ioOrderEditForm = ref<PlIoOrder | null>(null)
|
|
|
+ const ioOrderEditImagesCsv = ref('')
|
|
|
+
|
|
|
+ const ioOrderImageCsv = computed(() =>
|
|
|
+ Array.isArray(ioOrder.value?.siteFeedbackImages)
|
|
|
+ ? ioOrder.value!.siteFeedbackImages!.filter(Boolean).join(',')
|
|
|
+ : ''
|
|
|
+ )
|
|
|
+
|
|
|
+ const ioOrderHasFeedback = computed(() =>
|
|
|
+ Boolean(
|
|
|
+ ioOrder.value?.siteFeedbackRemark ||
|
|
|
+ (ioOrder.value?.siteFeedbackImages && ioOrder.value.siteFeedbackImages.length) ||
|
|
|
+ ioOrder.value?.siteFeedbackTime
|
|
|
+ )
|
|
|
+ )
|
|
|
+
|
|
|
+ const ioOrderViewFields = computed((): ViewField[] => {
|
|
|
+ if (!ioOrder.value) return []
|
|
|
+ const statusMap: Record<string, string> = {
|
|
|
+ in_progress: '进行中',
|
|
|
+ completed: '已完成',
|
|
|
+ voided: '已作废'
|
|
|
+ }
|
|
|
+ const status = ioOrder.value.status
|
|
|
+ return [
|
|
|
+ { label: '单号', value: ioOrder.value.orderNo },
|
|
|
+ {
|
|
|
+ label: '状态',
|
|
|
+ value: statusMap[status] || status,
|
|
|
+ tagType:
|
|
|
+ status === 'completed' ? 'success' : status === 'voided' ? 'info' : 'warning'
|
|
|
+ },
|
|
|
+ { label: '计划号', value: ioOrder.value.planNo },
|
|
|
+ { label: '车牌', value: ioOrder.value.vehicleNo },
|
|
|
+ { label: '往来单位', value: ioOrder.value.partnerCompany },
|
|
|
+ {
|
|
|
+ label: '最近提交',
|
|
|
+ value: formatDateTime(ioOrder.value.siteFeedbackTime) || '—'
|
|
|
+ },
|
|
|
+ { label: '取货地址', value: ioOrder.value.pickupAddress, span: 'full' },
|
|
|
+ { label: '取货时间', value: formatDateTime(ioOrder.value.pickupTime) || '—' },
|
|
|
+ { label: '取货注意事项', value: ioOrder.value.pickupNotes, span: 'full' },
|
|
|
+ {
|
|
|
+ label: '送货地址',
|
|
|
+ value: ioOrder.value.destinationAddress || ioOrder.value.destinationName,
|
|
|
+ span: 'full'
|
|
|
+ },
|
|
|
+ { label: '送达时间', value: formatDateTime(ioOrder.value.deliveryTime) || '—' },
|
|
|
+ { label: '送货注意事项', value: ioOrder.value.destinationNotes, span: 'full' }
|
|
|
+ ]
|
|
|
+ })
|
|
|
+
|
|
|
+ function openIoOrderEditDialog() {
|
|
|
+ if (!ioOrder.value) return
|
|
|
+ ioOrderEditForm.value = {
|
|
|
+ ...ioOrder.value,
|
|
|
+ items: (ioOrder.value.items || []).map(it => ({ ...it }))
|
|
|
+ }
|
|
|
+ ioOrderEditImagesCsv.value = ioOrderImageCsv.value
|
|
|
+ ioOrderEditVisible.value = true
|
|
|
+ }
|
|
|
+
|
|
|
+ async function saveIoOrderEdit() {
|
|
|
+ if (!ioOrderEditForm.value) return
|
|
|
+ const api = ioOrderEditForm.value.kind === 'inbound' ? inboundOrderApi : outboundOrderApi
|
|
|
+ ioOrderSaving.value = true
|
|
|
+ try {
|
|
|
+ const images = ioOrderEditImagesCsv.value
|
|
|
+ ? ioOrderEditImagesCsv.value.split(',').map(s => s.trim()).filter(Boolean)
|
|
|
+ : []
|
|
|
+ await api.patch(ioOrderEditForm.value.id, {
|
|
|
+ siteFeedbackRemark: ioOrderEditForm.value.siteFeedbackRemark,
|
|
|
+ siteFeedbackImages: images,
|
|
|
+ items: (ioOrderEditForm.value.items || []).map(it => ({
|
|
|
+ id: it.id,
|
|
|
+ actualQty: it.actualQty
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ ElMessage.success('保存成功')
|
|
|
+ ioOrderEditVisible.value = false
|
|
|
+ reload()
|
|
|
+ } catch (e) {
|
|
|
+ ElMessage.error(e instanceof Error ? e.message : '保存失败')
|
|
|
+ } finally {
|
|
|
+ ioOrderSaving.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const feedbackImageList = computed(() => parsePlFeedbackImages(transport.value?.feedbackImages))
|
|
|
|
|
|
const feedbackImageCsv = computed(() => feedbackImageList.value.join(','))
|