chore: sync release updates
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import axios from "axios";
|
||||
import request from "./request";
|
||||
import type { AdminSessionInfo } from "../utils/auth";
|
||||
|
||||
@@ -21,6 +22,59 @@ export interface AdminFileAsset {
|
||||
mime_type?: string;
|
||||
}
|
||||
|
||||
export type AdminUploadScene = "appraisal_evidence" | "zhongjian_report" | "warehouse_inbound_evidence" | "warehouse_return_packing";
|
||||
|
||||
export interface AdminDirectUploadPolicy {
|
||||
enabled: boolean;
|
||||
upload_url?: string;
|
||||
form_data?: Record<string, string | number>;
|
||||
asset?: AdminFileAsset;
|
||||
max_size?: number;
|
||||
max_size_text?: string;
|
||||
expires_at?: string;
|
||||
}
|
||||
|
||||
async function uploadFileToOss(uploadUrl: string, formData: Record<string, string | number>, file: File) {
|
||||
const ossFormData = new FormData();
|
||||
Object.entries(formData).forEach(([key, value]) => {
|
||||
ossFormData.append(key, String(value));
|
||||
});
|
||||
ossFormData.append("file", file);
|
||||
|
||||
await axios.post(uploadUrl, ossFormData, { timeout: 300000 });
|
||||
}
|
||||
|
||||
async function uploadManagedAdminFile(file: File, scene: AdminUploadScene, fallbackUrl: string, fallbackFields: Record<string, string | number> = {}) {
|
||||
const policyResponse = await request.post("/api/admin/file-upload/direct-policy", {
|
||||
upload_scene: scene,
|
||||
original_name: file.name,
|
||||
file_size: file.size,
|
||||
mime_type: file.type,
|
||||
}) as { code: number; message: string; data: AdminDirectUploadPolicy };
|
||||
|
||||
const policy = policyResponse.data;
|
||||
if (!policy.enabled) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("upload_scene", scene);
|
||||
Object.entries(fallbackFields).forEach(([key, value]) => {
|
||||
formData.append(key, String(value));
|
||||
});
|
||||
return request.post(fallbackUrl, formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
}) as Promise<{ code: number; message: string; data: AdminFileAsset }>;
|
||||
}
|
||||
|
||||
if (!policy.upload_url || !policy.form_data || !policy.asset) {
|
||||
throw new Error("OSS 上传签名无效,请稍后重试");
|
||||
}
|
||||
|
||||
await uploadFileToOss(policy.upload_url, policy.form_data, file);
|
||||
return { code: 0, message: "ok", data: policy.asset };
|
||||
}
|
||||
|
||||
export interface AdminTransferFlowSummary {
|
||||
id: number;
|
||||
internal_tag_no: string;
|
||||
@@ -1800,24 +1854,12 @@ export const adminApi = {
|
||||
};
|
||||
}>;
|
||||
},
|
||||
uploadAppraisalEvidenceFile(file: File) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
return request.post("/api/admin/appraisal-task/evidence/upload", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
}) as Promise<{
|
||||
uploadAppraisalEvidenceFile(file: File, scene: AdminUploadScene = "appraisal_evidence", taskId?: number) {
|
||||
const fallbackFields: Record<string, string | number> = taskId ? { task_id: taskId } : {};
|
||||
return uploadManagedAdminFile(file, scene, "/api/admin/appraisal-task/evidence/upload", fallbackFields) as Promise<{
|
||||
code: number;
|
||||
message: string;
|
||||
data: {
|
||||
file_id: string;
|
||||
file_url: string;
|
||||
thumbnail_url: string;
|
||||
name?: string;
|
||||
file_type?: string;
|
||||
mime_type?: string;
|
||||
};
|
||||
data: AdminFileAsset;
|
||||
}>;
|
||||
},
|
||||
deleteAppraisalEvidenceFile(fileUrl: string) {
|
||||
@@ -1888,14 +1930,15 @@ export const adminApi = {
|
||||
internal_tag_no: internalTagNo,
|
||||
}) as Promise<{ code: number; message: string; data: AdminWarehouseWorkbenchContext }>;
|
||||
},
|
||||
uploadWarehouseInboundEvidenceFile(file: File) {
|
||||
return uploadManagedAdminFile(file, "warehouse_inbound_evidence", "/api/admin/warehouse-workbench/inbound/evidence/upload") as Promise<{
|
||||
code: number;
|
||||
message: string;
|
||||
data: AdminFileAsset;
|
||||
}>;
|
||||
},
|
||||
uploadWarehouseReturnPackingFile(file: File) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
return request.post("/api/admin/warehouse-workbench/return/packing/upload", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
}) as Promise<{
|
||||
return uploadManagedAdminFile(file, "warehouse_return_packing", "/api/admin/warehouse-workbench/return/packing/upload") as Promise<{
|
||||
code: number;
|
||||
message: string;
|
||||
data: AdminFileAsset;
|
||||
|
||||
@@ -579,6 +579,9 @@ function triggerEvidenceUpload() {
|
||||
}
|
||||
|
||||
async function handleEvidenceFileSelect(event: Event) {
|
||||
if (!detail.value) {
|
||||
return;
|
||||
}
|
||||
const target = event.target as HTMLInputElement;
|
||||
const files = Array.from(target.files || []);
|
||||
if (!files.length) {
|
||||
@@ -588,7 +591,7 @@ async function handleEvidenceFileSelect(event: Event) {
|
||||
evidenceUploading.value = true;
|
||||
try {
|
||||
for (const file of files) {
|
||||
const response = await adminApi.uploadAppraisalEvidenceFile(file);
|
||||
const response = await adminApi.uploadAppraisalEvidenceFile(file, "appraisal_evidence", detail.value.task_info.id);
|
||||
resultAttachments.value.push(response.data);
|
||||
}
|
||||
ElMessage.success("附件上传成功");
|
||||
@@ -609,6 +612,9 @@ function triggerZhongjianReportUpload() {
|
||||
}
|
||||
|
||||
async function handleZhongjianReportFileSelect(event: Event) {
|
||||
if (!detail.value) {
|
||||
return;
|
||||
}
|
||||
const target = event.target as HTMLInputElement;
|
||||
const files = Array.from(target.files || []);
|
||||
if (!files.length) {
|
||||
@@ -618,7 +624,7 @@ async function handleZhongjianReportFileSelect(event: Event) {
|
||||
zhongjianReportUploading.value = true;
|
||||
try {
|
||||
for (const file of files) {
|
||||
const response = await adminApi.uploadAppraisalEvidenceFile(file);
|
||||
const response = await adminApi.uploadAppraisalEvidenceFile(file, "zhongjian_report", detail.value.task_info.id);
|
||||
zhongjianReportFiles.value.push(response.data);
|
||||
}
|
||||
ElMessage.success("中检报告文件已上传");
|
||||
|
||||
@@ -596,6 +596,16 @@ watch(
|
||||
<div class="detail-label">说明</div>
|
||||
<div class="detail-value">{{ detail.result_info.result_desc || "-" }}</div>
|
||||
</div>
|
||||
<template v-if="detail.result_info.key_points?.length">
|
||||
<div v-for="(item, index) in detail.result_info.key_points" :key="`${item.point_code || item.point_name}-${index}`" class="detail-card__desc">
|
||||
<div class="detail-label">{{ item.point_name || "鉴定项" }}</div>
|
||||
<div class="detail-value">{{ [item.point_value, item.point_remark].filter(Boolean).join(";") || "-" }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="detail.result_info.external_remark" class="detail-card__desc">
|
||||
<div class="detail-label">对外备注</div>
|
||||
<div class="detail-value">{{ detail.result_info.external_remark }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
@@ -634,6 +644,10 @@ watch(
|
||||
<div class="detail-label">成色评级</div>
|
||||
<div class="detail-value">{{ detail.valuation_info.condition_grade || "-" }}</div>
|
||||
</div>
|
||||
<div class="detail-card__desc">
|
||||
<div class="detail-label">成色说明</div>
|
||||
<div class="detail-value">{{ detail.valuation_info.condition_desc || "-" }}</div>
|
||||
</div>
|
||||
<div class="detail-card__desc">
|
||||
<div class="detail-label">估值区间</div>
|
||||
<div class="detail-value">¥{{ detail.valuation_info.valuation_min || 0 }} - ¥{{ detail.valuation_info.valuation_max || 0 }}</div>
|
||||
|
||||
@@ -20,6 +20,7 @@ const returnTagNo = ref("");
|
||||
const returnMaterialQr = ref("");
|
||||
const returnExpressCompany = ref("");
|
||||
const returnTrackingNo = ref("");
|
||||
const inboundAttachments = ref<AdminFileAsset[]>([]);
|
||||
const returnPackingAttachments = ref<AdminFileAsset[]>([]);
|
||||
|
||||
const inboundContext = ref<AdminWarehouseWorkbenchContext | null>(null);
|
||||
@@ -34,6 +35,7 @@ const returnTrackingInputRef = ref<InputInstance | null>(null);
|
||||
const returnReviewDrawerVisible = ref(false);
|
||||
const returnReviewLoading = ref(false);
|
||||
const returnConfirmLoading = ref(false);
|
||||
const inboundUploading = ref(false);
|
||||
const returnPackingUploading = ref(false);
|
||||
|
||||
const currentReturnIsZhongjian = computed(() => returnContext.value?.order_info.service_provider === "zhongjian");
|
||||
@@ -157,6 +159,7 @@ async function lookupInbound() {
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
inboundAttachments.value = [];
|
||||
const response = await adminApi.lookupWarehouseInbound(trackingNo);
|
||||
inboundContext.value = response.data;
|
||||
ElMessage.success("已匹配订单");
|
||||
@@ -179,13 +182,19 @@ async function receiveInbound() {
|
||||
ElMessage.warning("请扫描内部流转挂牌");
|
||||
return;
|
||||
}
|
||||
if (inboundUploading.value) {
|
||||
ElMessage.warning("入库附件上传中,请稍后提交");
|
||||
return;
|
||||
}
|
||||
actionLoading.value = true;
|
||||
try {
|
||||
const response = await adminApi.receiveWarehouseInbound({
|
||||
inbound_no: inboundTrackingNo.value.trim(),
|
||||
internal_tag_no: inboundTagNo.value.trim(),
|
||||
inbound_attachments: inboundAttachments.value,
|
||||
});
|
||||
inboundContext.value = response.data;
|
||||
inboundAttachments.value = [];
|
||||
ElMessage.success("入库完成");
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.message || "入库失败");
|
||||
@@ -194,6 +203,28 @@ async function receiveInbound() {
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadInboundAttachment(options: { file: File }) {
|
||||
inboundUploading.value = true;
|
||||
try {
|
||||
const response = await adminApi.uploadWarehouseInboundEvidenceFile(options.file);
|
||||
if (response.code !== 0) {
|
||||
ElMessage.error(response.message || "入库附件上传失败");
|
||||
return;
|
||||
}
|
||||
inboundAttachments.value.push(response.data);
|
||||
ElMessage.success("入库附件已上传");
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
ElMessage.error(error?.message || "入库附件上传失败");
|
||||
} finally {
|
||||
inboundUploading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function removeInboundAttachment(fileUrl: string) {
|
||||
inboundAttachments.value = inboundAttachments.value.filter((item) => item.file_url !== fileUrl);
|
||||
}
|
||||
|
||||
async function lookupZhongjian() {
|
||||
if (!zhongjianTagNo.value.trim()) {
|
||||
ElMessage.warning("请扫描内部流转码");
|
||||
@@ -442,7 +473,30 @@ function openFile(url: string) {
|
||||
<el-input ref="inboundTagInputRef" v-model="inboundTagNo" size="large" placeholder="扫描内部流转挂牌" clearable @keyup.enter="receiveInbound" />
|
||||
<div class="actions-row">
|
||||
<el-button type="primary" :loading="loading" @click="lookupInbound">匹配订单</el-button>
|
||||
<el-button type="success" :loading="actionLoading" :disabled="!inboundContext" @click="receiveInbound">绑定挂牌并入库</el-button>
|
||||
<el-button type="success" :loading="actionLoading" :disabled="!inboundContext || inboundUploading" @click="receiveInbound">绑定挂牌并入库</el-button>
|
||||
</div>
|
||||
<div v-if="inboundContext" class="packing-upload">
|
||||
<div class="packing-upload-head">
|
||||
<el-upload
|
||||
:show-file-list="false"
|
||||
:http-request="uploadInboundAttachment"
|
||||
:disabled="inboundUploading"
|
||||
accept="image/*,video/*"
|
||||
multiple
|
||||
>
|
||||
<el-button :loading="inboundUploading">上传拆包图片/视频</el-button>
|
||||
</el-upload>
|
||||
<span class="packing-upload-hint">{{ inboundAttachments.length }} 个入库附件</span>
|
||||
</div>
|
||||
<div v-if="inboundAttachments.length" class="packing-file-list">
|
||||
<div v-for="file in inboundAttachments" :key="file.file_url" class="packing-file-item">
|
||||
<button class="file-button" type="button" @click="openFile(file.file_url)">
|
||||
{{ file.name || file.file_url }}
|
||||
</button>
|
||||
<span class="packing-file-type">{{ fileTypeText(file) }}</span>
|
||||
<el-button link type="danger" @click="removeInboundAttachment(file.file_url)">移除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
Reference in New Issue
Block a user