| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="section-card"> |
| | | <view class="section-head"> |
| | | <text class="section-title">填报内容</text> |
| | | <text class="section-title">{{ isSpecialApprovalType ? specialDetailTitle : "填报内容" }}</text> |
| | | </view> |
| | | <view v-if="displayFields.length" |
| | | class="info-rows"> |
| | | <view v-for="field in displayFields" |
| | | :key="field.key" |
| | | class="info-row"> |
| | | <text class="info-label">{{ field.label }}</text> |
| | | <text class="info-value">{{ displayFieldValue(field) }}</text> |
| | | <!-- 采购/报价/发货审批:展示业务单据详情(与 Web approve-list 一致) --> |
| | | <template v-if="isSpecialApprovalType"> |
| | | <view v-if="businessDetailLoading" |
| | | class="empty-hint">加载中...</view> |
| | | <view v-else-if="!hasBusinessDetail" |
| | | class="empty-hint">{{ specialDetailEmptyText }}</view> |
| | | <view v-else |
| | | class="info-rows"> |
| | | <view v-for="(item, idx) in specialDetailRows" |
| | | :key="`special-${idx}`" |
| | | class="info-row"> |
| | | <text class="info-label">{{ item.label }}</text> |
| | | <text class="info-value">{{ item.value }}</text> |
| | | </view> |
| | | </view> |
| | | <view v-for="(extra, idx) in moduleExtraRows" |
| | | :key="`extra-${idx}`" |
| | | class="info-row"> |
| | | <text class="info-label">{{ extra.label }}</text> |
| | | <text class="info-value">{{ extra.value }}</text> |
| | | </template> |
| | | <template v-else> |
| | | <view v-if="displayFields.length" |
| | | class="info-rows"> |
| | | <view v-for="field in displayFields" |
| | | :key="field.key" |
| | | class="info-row"> |
| | | <text class="info-label">{{ field.label }}</text> |
| | | <text class="info-value">{{ displayFieldValue(field) }}</text> |
| | | </view> |
| | | <view v-for="(extra, idx) in moduleExtraRows" |
| | | :key="`extra-${idx}`" |
| | | class="info-row"> |
| | | <text class="info-label">{{ extra.label }}</text> |
| | | <text class="info-value">{{ extra.value }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="empty-hint">暂无填报内容</view> |
| | | <view v-else |
| | | class="empty-hint">暂无填报内容</view> |
| | | </template> |
| | | </view> |
| | | |
| | | <view class="section-card"> |
| | | <view class="section-head"> |
| | | <text class="section-title">审批流程({{ flowNodes.length }} 项)</text> |
| | |
| | | <view v-else |
| | | class="empty-hint">暂无流程节点</view> |
| | | </view> |
| | | |
| | | <view class="section-card"> |
| | | <view class="section-head"> |
| | | <text class="section-title">审批记录</text> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed } from "vue"; |
| | | import { computed, ref, watch } from "vue"; |
| | | import { APPROVAL_MODULE_KEYS } from "../../../_utils/approvalModuleRegistry.js"; |
| | | import { getQuotationList } from "@/api/salesManagement/salesQuotation"; |
| | | import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger"; |
| | | import { getDeliveryDetailByShippingNo } from "@/api/collaborativeApproval/approvalProcess"; |
| | | import { |
| | | computeLeaveDurationDisplay, |
| | | computeOvertimeHoursDisplay, |
| | |
| | | moduleKey: { type: String, default: "" }, |
| | | }); |
| | | |
| | | const LEVEL_TEXT = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"]; |
| | | const LEVEL_TEXT = [ |
| | | "", |
| | | "一", |
| | | "二", |
| | | "三", |
| | | "四", |
| | | "五", |
| | | "六", |
| | | "七", |
| | | "八", |
| | | "九", |
| | | "十", |
| | | ]; |
| | | |
| | | const isBusinessModule = computed(() => |
| | | [ |
| | |
| | | ); |
| | | |
| | | const statusLabel = status => |
| | | isBusinessModule.value ? businessStatusText(status) : instanceStatusText(status); |
| | | isBusinessModule.value |
| | | ? businessStatusText(status) |
| | | : instanceStatusText(status); |
| | | |
| | | const statusTagType = status => |
| | | isBusinessModule.value ? businessStatusTagType(status) : instanceStatusTagType(status); |
| | | isBusinessModule.value |
| | | ? businessStatusTagType(status) |
| | | : instanceStatusTagType(status); |
| | | |
| | | const displayFields = computed(() => resolveInstanceDisplayFields(props.row)); |
| | | |
| | |
| | | |
| | | const flowNodes = computed(() => mapTasksToFlowNodes(props.row?.tasks)); |
| | | |
| | | const approvalRecords = computed(() => |
| | | mapApprovalRecords(props.row?.records) |
| | | ); |
| | | const approvalRecords = computed(() => mapApprovalRecords(props.row?.records)); |
| | | |
| | | const rejectReason = computed(() => |
| | | getRejectReasonFromRecords(props.row?.records) |
| | | ); |
| | | |
| | | const levelLabel = n => LEVEL_TEXT[Number(n)] || String(n); |
| | | |
| | | /** 采购/报价/发货审批:业务单据详情(与 Web approve-list 一致) */ |
| | | const SPECIAL_BUSINESS_TYPES = [5, 6, 7]; |
| | | |
| | | const businessType = computed(() => Number(props.row?.businessType)); |
| | | const isSpecialApprovalType = computed(() => |
| | | SPECIAL_BUSINESS_TYPES.includes(businessType.value) |
| | | ); |
| | | |
| | | const businessDetail = ref({}); |
| | | const businessProductList = ref([]); |
| | | const businessDetailLoading = ref(false); |
| | | |
| | | const specialDetailTitle = computed(() => { |
| | | if (businessType.value === 5) return "采购详情"; |
| | | if (businessType.value === 6) return "报价详情"; |
| | | return "发货详情"; |
| | | }); |
| | | |
| | | const specialDetailEmptyText = computed(() => { |
| | | if (businessType.value === 5) return "未查询到对应采购详情"; |
| | | if (businessType.value === 6) return "未查询到对应报价详情"; |
| | | return "未查询到对应发货详情"; |
| | | }); |
| | | |
| | | const hasBusinessDetail = computed(() => { |
| | | const d = businessDetail.value || {}; |
| | | if (businessType.value === 5) return Boolean(d.purchaseContractNumber); |
| | | if (businessType.value === 6) return Boolean(d.quotationNo); |
| | | if (businessType.value === 7) return Boolean(d.shippingInfo); |
| | | return false; |
| | | }); |
| | | |
| | | const formatMoney = val => `¥${Number(val ?? 0).toFixed(2)}`; |
| | | |
| | | const joinDesc = parts => parts.filter(Boolean).join(" · "); |
| | | |
| | | const specialDetailRows = computed(() => { |
| | | const d = businessDetail.value || {}; |
| | | const products = businessProductList.value || []; |
| | | const rows = []; |
| | | const push = (label, value) => rows.push({ label, value: value || "--" }); |
| | | |
| | | if (businessType.value === 6) { |
| | | push("报价单号", d.quotationNo); |
| | | push("客户名称", d.customer); |
| | | push("业务员", d.salesperson); |
| | | push("报价日期", d.quotationDate); |
| | | push("有效期至", d.validDate); |
| | | push("付款方式", d.paymentMethod); |
| | | push("报价总额", formatMoney(d.totalAmount)); |
| | | products.forEach((p, i) => { |
| | | push( |
| | | p.product || `产品${i + 1}`, |
| | | joinDesc([p.specification, p.unit, formatMoney(p.unitPrice)]) |
| | | ); |
| | | }); |
| | | if (d.remark) push("备注", d.remark); |
| | | } else if (businessType.value === 5) { |
| | | push("采购合同号", d.purchaseContractNumber); |
| | | push("供应商名称", d.supplierName); |
| | | push("项目名称", d.projectName); |
| | | push("销售合同号", d.salesContractNo); |
| | | push("签订日期", d.executionDate); |
| | | push("录入日期", d.entryDate); |
| | | push("付款方式", d.paymentMethod); |
| | | push("合同金额", formatMoney(d.contractAmount)); |
| | | products.forEach((p, i) => { |
| | | push( |
| | | p.productCategory || `产品${i + 1}`, |
| | | joinDesc([ |
| | | p.specificationModel, |
| | | p.quantity != null && p.quantity !== "" |
| | | ? `${p.quantity}${p.unit || ""}` |
| | | : "", |
| | | `含税单价 ${formatMoney(p.taxInclusiveUnitPrice)}`, |
| | | `含税总价 ${formatMoney(p.taxInclusiveTotalPrice)}`, |
| | | ]) |
| | | ); |
| | | }); |
| | | } else if (businessType.value === 7) { |
| | | const info = d.shippingInfo || {}; |
| | | push("销售订单", info.salesContractNo); |
| | | push("发货订单号", info.shippingNo); |
| | | push("客户名称", info.customerName); |
| | | push("发货类型", info.type); |
| | | push("发货日期", info.shippingDate); |
| | | push("审核状态", info.status); |
| | | push("发货车牌号", info.shippingCarNumber); |
| | | push("快递公司", info.expressCompany); |
| | | push("快递单号", info.expressNumber); |
| | | products.forEach((p, i) => { |
| | | push( |
| | | p.productName || `产品${i + 1}`, |
| | | joinDesc([ |
| | | p.batchNo ? `批号 ${p.batchNo}` : "", |
| | | p.specificationModel, |
| | | p.deliveryQuantity != null ? `发货数量 ${p.deliveryQuantity}` : "", |
| | | ]) |
| | | ); |
| | | }); |
| | | } |
| | | return rows; |
| | | }); |
| | | |
| | | async function loadBusinessDetail() { |
| | | const row = props.row || {}; |
| | | const type = Number(row.businessType); |
| | | businessDetail.value = {}; |
| | | businessProductList.value = []; |
| | | if (!SPECIAL_BUSINESS_TYPES.includes(type)) return; |
| | | |
| | | businessDetailLoading.value = true; |
| | | try { |
| | | if (type === 6) { |
| | | if (!row.quotationNo) return; |
| | | const res = await getQuotationList({ quotationNo: row.quotationNo }); |
| | | const hit = res?.data?.records?.[0] || {}; |
| | | businessDetail.value = hit; |
| | | businessProductList.value = hit.products || []; |
| | | } else if (type === 5) { |
| | | if (!row.purchaseContractNumber) return; |
| | | const res = await getPurchaseByCode({ |
| | | purchaseContractNumber: row.purchaseContractNumber, |
| | | approvalInstanceId: row.id, |
| | | }); |
| | | const hit = res?.data || res || {}; |
| | | businessDetail.value = hit; |
| | | businessProductList.value = hit.productData || []; |
| | | } else if (type === 7) { |
| | | if (!row.shippingNo) return; |
| | | const res = await getDeliveryDetailByShippingNo({ |
| | | shippingNo: row.shippingNo, |
| | | }); |
| | | const hit = res?.data || res || {}; |
| | | businessDetail.value = hit; |
| | | businessProductList.value = hit.shippingProductDetailDtoList || []; |
| | | } |
| | | } catch { |
| | | businessDetail.value = {}; |
| | | businessProductList.value = []; |
| | | } finally { |
| | | businessDetailLoading.value = false; |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => [props.row?.id, props.row?.businessType], |
| | | () => { |
| | | loadBusinessDetail(); |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |