diff --git a/work-app/src/manifest.json b/work-app/src/manifest.json index 9fe13d7..d03523e 100644 --- a/work-app/src/manifest.json +++ b/work-app/src/manifest.json @@ -2,8 +2,8 @@ "name": "安心验作业端", "appid": "__UNI__E0C8390", "description": "安心验仓管与鉴定作业 Android App", - "versionName": "1.0.1", - "versionCode": "102", + "versionName": "1.0.2", + "versionCode": "103", "transformPx": false, "app-plus": { "usingComponents": true, diff --git a/work-app/src/pages/report/detail.vue b/work-app/src/pages/report/detail.vue index ece2caf..66662aa 100644 --- a/work-app/src/pages/report/detail.vue +++ b/work-app/src/pages/report/detail.vue @@ -4,6 +4,8 @@ import { onLoad, onShow } from "@dcloudio/uni-app"; import { adminApi, type AdminFileAsset, type AdminReportDetail } from "../../api/admin"; import { showErrorToast, showInfoToast } from "../../utils/feedback"; +type ReportTab = "product" | "attachments"; + const loading = ref(false); const pageReady = ref(false); const loadError = ref(""); @@ -11,74 +13,83 @@ const detail = ref(null); const reportId = ref(0); const returnInternalTagNo = ref(""); const returnConfirming = ref(false); +const activeTab = ref("product"); const activeVideo = ref(null); const isZhongjian = computed(() => detail.value?.report_header.service_provider === "zhongjian"); const isReturnReview = computed(() => Boolean(returnInternalTagNo.value && reportId.value)); -const reportMetaItems = computed(() => { - const current = detail.value; - if (!current) return []; - - const items = [ - { label: "发布时间", value: current.report_header.publish_time || "-" }, - ]; - const appraiserName = textValue(current.appraisal_info?.appraiser_name) - || textValue(current.report_header.report_entry_admin_name); - if (appraiserName) { - items.push({ label: "鉴定师", value: appraiserName }); - } - if (isZhongjian.value) { - items.push({ label: "中检报告号", value: current.report_header.zhongjian_report_no || "-" }); - items.push({ label: "报告录入人", value: current.report_header.report_entry_admin_name || "-" }); - } - - return items; -}); -const resultMetaItems = computed(() => { - const current = detail.value; - if (!current) return []; - - const result = current.result_info || {}; - const valuation = current.valuation_info || {}; - const items = [ - { label: "结论", value: textValue(result.result_text) || "-" }, - { label: "结论说明", value: textValue(result.result_desc) || "-" }, - ]; - - for (const point of normalizedKeyPoints(result.key_points)) { - items.push({ - label: point.point_name, - value: point.point_value || "-", - }); - } - - const conditionGrade = textValue(valuation.condition_grade); - const conditionDesc = textValue(valuation.condition_desc); - if (conditionGrade || conditionDesc) { - items.push({ label: "成色评级", value: [conditionGrade, conditionDesc].filter(Boolean).join(";") || "-" }); - } - - const valuationMin = Number(valuation.valuation_min || 0); - const valuationMax = Number(valuation.valuation_max || 0); - const valuationDesc = textValue(valuation.valuation_desc); - if (valuationMin > 0 || valuationMax > 0 || valuationDesc) { - const range = valuationMin > 0 || valuationMax > 0 ? `¥${valuationMin} - ¥${valuationMax}` : ""; - items.push({ label: "估值", value: [range, valuationDesc].filter(Boolean).join(";") || "-" }); - } - - const externalRemark = textValue(result.external_remark); - if (externalRemark) { - items.push({ label: "备注", value: externalRemark }); - } - - return items; -}); const evidenceAttachments = computed(() => detail.value?.evidence_attachments || []); const zhongjianReportFiles = computed(() => isZhongjian.value ? (detail.value?.zhongjian_report_files || []) : []); +const imageEvidenceList = computed(() => evidenceAttachments.value.filter(isImageAsset)); +const fileEvidenceList = computed(() => evidenceAttachments.value.filter((item) => !isImageAsset(item))); +const zhongjianImageFiles = computed(() => zhongjianReportFiles.value.filter(isImageAsset)); +const zhongjianOtherFiles = computed(() => zhongjianReportFiles.value.filter((item) => !isImageAsset(item))); +const reportImages = computed(() => { + if (imageEvidenceList.value.length) return imageEvidenceList.value; + return zhongjianImageFiles.value; +}); +const hasAttachments = computed(() => evidenceAttachments.value.length > 0 || zhongjianReportFiles.value.length > 0); +const reportNo = computed(() => textValue(detail.value?.report_header.report_no) || "-"); +const productName = computed(() => textValue(detail.value?.product_info?.product_name) || "-"); +const institutionName = computed(() => textValue(detail.value?.report_header.institution_name) || "-"); +const publishTime = computed(() => textValue(detail.value?.report_header.publish_time) || "-"); +const resultItem = computed(() => { + const result = detail.value?.result_info || {}; + return { + label: "检测结论", + value: textValue(result.result_text) || "-", + remark: textValue(result.result_desc), + }; +}); +const productSpecItems = computed(() => { + const current = detail.value; + if (!current) return []; -function previewImage(urls: string[], current: string) { - if (!urls.length) return; - uni.previewImage({ urls, current }); + const product = current.product_info || {}; + const result = current.result_info || {}; + const valuation = current.valuation_info || {}; + const items: Array<{ label: string; value: string; remark?: string }> = []; + + appendSpecItem(items, "品类", product.category_name); + appendSpecItem(items, "品牌", product.brand_name); + appendSpecItem(items, "颜色", product.color); + appendSpecItem(items, "规格/尺寸", product.size_spec); + appendSpecItem(items, "序列号/编码", product.serial_no); + + for (const point of normalizedKeyPoints(result.key_points)) { + appendSpecItem(items, point.point_name, point.point_value, point.point_remark); + } + + appendSpecItem(items, "服务类型", current.report_header.service_provider_text); + if (isZhongjian.value) { + appendSpecItem(items, "中检报告号", current.report_header.zhongjian_report_no); + appendSpecItem(items, "报告录入人", current.report_header.report_entry_admin_name); + } + + const appraiserName = textValue(current.appraisal_info?.appraiser_name) + || textValue(current.report_header.report_entry_admin_name); + appendSpecItem(items, "鉴定师", appraiserName); + appendSpecItem(items, "成色评级", valuation.condition_grade, valuation.condition_desc); + appendSpecItem(items, "估值区间", formatValuationRange(valuation.valuation_min, valuation.valuation_max), valuation.valuation_desc); + appendSpecItem(items, "备注", result.external_remark); + + return items; +}); + +function appendSpecItem( + items: Array<{ label: string; value: string; remark?: string }>, + label: string, + value: unknown, + remark: unknown = "", +) { + const valueText = textValue(value); + const remarkText = textValue(remark); + if (!valueText && !remarkText) return; + items.push({ + label, + value: valueText || "-", + remark: remarkText, + }); } function textValue(value: unknown) { @@ -97,7 +108,25 @@ function normalizedKeyPoints(value: unknown) { point_remark: textValue(point.point_remark), }; }) - .filter((item) => item.point_value); + .filter((item) => item.point_value || item.point_remark); +} + +function formatValuationRange(min: unknown, max: unknown) { + const minValue = Number(min || 0); + const maxValue = Number(max || 0); + if (minValue <= 0 && maxValue <= 0) return ""; + if (minValue > 0 && maxValue > 0) return `¥${formatMoney(minValue)} - ¥${formatMoney(maxValue)}`; + if (minValue > 0) return `¥${formatMoney(minValue)} 起`; + return `¥${formatMoney(maxValue)} 内`; +} + +function formatMoney(value: number) { + return String(Number(value.toFixed(2))).replace(/\.0+$/, ""); +} + +function previewImage(urls: string[], current: string) { + if (!urls.length) return; + uni.previewImage({ urls, current }); } function isImageAsset(item: AdminFileAsset) { @@ -115,13 +144,13 @@ function assetTypeLabel(item: AdminFileAsset) { return "附件"; } -function openAsset(item: AdminFileAsset) { +function assetDisplayName(item: AdminFileAsset, index: number) { + return item.name || `${assetTypeLabel(item)} ${index + 1}`; +} + +function openAsset(item: AdminFileAsset, files: AdminFileAsset[]) { if (isImageAsset(item)) { - const urls = [ - ...evidenceAttachments.value.filter(isImageAsset).map((asset) => asset.file_url), - ...zhongjianReportFiles.value.filter(isImageAsset).map((asset) => asset.file_url), - ]; - previewImage(urls, item.file_url); + previewImage(files.filter(isImageAsset).map((asset) => asset.file_url), item.file_url); return; } @@ -227,112 +256,152 @@ onShow(() => {