feat: update report detail and verification flow

This commit is contained in:
wushumin
2026-05-22 13:31:02 +08:00
parent b98d6164a7
commit be64b8e5b7
14 changed files with 1336 additions and 282 deletions

View File

@@ -24,6 +24,12 @@ const valuationDesc = ref("");
const externalRemark = ref("");
const internalRemark = ref("");
const zhongjianReportNo = ref("");
const productName = ref("");
const categoryName = ref("");
const brandName = ref("");
const color = ref("");
const sizeSpec = ref("");
const serialNo = ref("");
const zhongjianFiles = ref<AdminFileAsset[]>([]);
const evidenceFiles = ref<AdminFileAsset[]>([]);
const activePreviewVideo = ref<AdminFileAsset | null>(null);
@@ -86,6 +92,12 @@ function hydrate(detailData: AdminAppraisalTaskDetail) {
externalRemark.value = detailData.result_info.external_remark || "";
internalRemark.value = detailData.result_info.internal_remark || "";
zhongjianReportNo.value = detailData.zhongjian_report?.report_no || "";
productName.value = detailData.product_info.product_name || "";
categoryName.value = detailData.product_info.category_name || "";
brandName.value = detailData.product_info.brand_name || "";
color.value = detailData.product_info.color || "";
sizeSpec.value = detailData.product_info.size_spec || "";
serialNo.value = detailData.product_info.serial_no || "";
zhongjianFiles.value = [...(detailData.zhongjian_report?.files || [])];
evidenceFiles.value = [...(detailData.result_info.attachments || [])];
@@ -553,6 +565,14 @@ async function submitZhongjianReport() {
showInfoToast("请填写中检报告编号");
return;
}
if (!resultText.value.trim()) {
showInfoToast("请填写鉴定结论");
return;
}
if (!productName.value.trim() && !categoryName.value.trim() && !brandName.value.trim()) {
showInfoToast("请先完善物品信息");
return;
}
if (!zhongjianFiles.value.length) {
showInfoToast("请至少上传 1 个中检报告文件");
return;
@@ -568,6 +588,19 @@ async function submitZhongjianReport() {
await adminApi.saveZhongjianAppraisalReport({
id: detail.value.task_info.id,
zhongjian_report_no: zhongjianReportNo.value.trim(),
product_info: {
category_id: detail.value.product_info.category_id,
product_name: productName.value.trim(),
category_name: categoryName.value.trim(),
brand_name: brandName.value.trim(),
color: color.value.trim(),
size_spec: sizeSpec.value.trim(),
serial_no: serialNo.value.trim(),
},
result_text: resultText.value.trim(),
result_desc: resultDesc.value.trim(),
attachments: evidenceFiles.value,
key_points: templateKeyPointsPayload(),
report_files: zhongjianFiles.value,
qr_input: qrInput,
});
@@ -764,6 +797,77 @@ onShow(() => {
<view v-else class="card">
<view class="card-title">中检报告</view>
<view class="stack" style="margin-top: 18rpx">
<view class="card-desc">报告展示信息</view>
<input v-model="productName" class="field" :disabled="isTaskReadonly" placeholder="产品名称" />
<input v-model="categoryName" class="field" :disabled="isTaskReadonly" placeholder="品类" />
<input v-model="brandName" class="field" :disabled="isTaskReadonly" placeholder="品牌" />
<view class="meta-grid">
<input v-model="color" class="field" :disabled="isTaskReadonly" placeholder="颜色" />
<input v-model="sizeSpec" class="field" :disabled="isTaskReadonly" placeholder="规格 / 尺寸" />
</view>
<input v-model="serialNo" class="field" :disabled="isTaskReadonly" placeholder="序列号 / 编码" />
<textarea v-model="resultText" class="textarea" :disabled="isTaskReadonly" placeholder="鉴定结论" />
<textarea v-model="resultDesc" class="textarea" :disabled="isTaskReadonly" placeholder="结论说明" />
<view v-if="detail.appraisal_template?.key_points?.length" class="stack">
<view class="card-desc">模板项</view>
<view v-for="(item, index) in detail.appraisal_template.key_points" :key="`zhongjian-${item.point_code}`" class="stack">
<view class="meta-item">
<view class="meta-label">{{ item.point_name }}</view>
<view class="meta-value">{{ item.point_type }}{{ item.is_required ? " · 必填" : "" }}</view>
</view>
<input
:value="item.point_value"
class="field"
:disabled="isTaskReadonly"
:placeholder="`${item.point_name} 值`"
@input="updateTemplatePointFromInput(index, 'point_value', $event)"
/>
<textarea
:value="item.point_remark"
class="textarea"
:disabled="isTaskReadonly"
:placeholder="`${item.point_name} 说明`"
@input="updateTemplatePointFromInput(index, 'point_remark', $event)"
/>
</view>
</view>
<view class="card-desc evidence-title">鉴定图片 / 视频</view>
<view v-if="evidenceFiles.length" class="attachment-grid">
<view v-for="item in evidenceFiles" :key="`zj-evidence-${item.file_url}`" class="attachment-tile">
<view class="attachment-preview" @click="previewAttachment(evidenceFiles, item)">
<image v-if="isImageAsset(item)" class="attachment-thumb" :src="item.thumbnail_url || item.file_url" mode="aspectFill" />
<template v-else-if="isVideoAsset(item)">
<image v-if="item.thumbnail_url" class="attachment-thumb" :src="item.thumbnail_url" mode="aspectFill" />
<view v-else class="attachment-video-thumb">
<text class="attachment-video-label">视频</text>
</view>
</template>
<view v-else class="attachment-file-thumb">附件</view>
<view v-if="isVideoAsset(item)" class="attachment-play" @click.stop="previewAttachment(evidenceFiles, item)"></view>
</view>
<view class="attachment-meta">
<view class="attachment-name">{{ item.name || item.file_id }}</view>
<view class="attachment-actions">
<text class="attachment-type">{{ attachmentTypeLabel(item) }}</text>
<text v-if="!isTaskReadonly" class="attachment-remove" @click.stop="removeEvidenceFile(item.file_url)">删除</text>
</view>
</view>
</view>
</view>
<view v-if="!isTaskReadonly" class="upload-actions">
<button class="action-button action-button--secondary" :disabled="uploading" @click="chooseEvidenceImage">
<text class="action-symbol">+</text>
<text>{{ uploading ? "上传中" : "添加鉴定图片" }}</text>
</button>
<button class="action-button action-button--secondary" :disabled="uploading" @click="chooseEvidenceVideo">
<text class="action-symbol">+</text>
<text>{{ uploading ? "上传中" : "添加鉴定视频" }}</text>
</button>
</view>
<view class="card-desc">中检报告文件</view>
<input v-model="zhongjianReportNo" class="field" :disabled="isTaskReadonly" placeholder="中检报告编号" />
<view v-if="zhongjianFiles.length" class="attachment-grid">
<view v-for="item in zhongjianFiles" :key="item.file_url" class="attachment-tile">