Files
anxinyan/work-app/src/api/admin.ts
2026-05-22 21:13:52 +08:00

631 lines
18 KiB
TypeScript

import { request, uploadDirectFile, uploadFile } from "../utils/request";
import type { AdminSessionInfo } from "../utils/auth";
export interface AdminLoginResponse {
token: string;
admin_info: AdminSessionInfo;
}
export interface AdminFileAsset {
file_id: string;
file_url: string;
thumbnail_url: string;
name?: string;
file_type?: string;
mime_type?: string;
}
export interface AdminDirectUploadMeta {
original_name?: string;
file_size?: number;
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;
}
export interface AdminExpressCompanyItem {
id: number;
company_name: string;
company_code: string;
status: string;
status_text: string;
is_default: boolean;
sort_order: number;
remark: string;
created_at: string;
updated_at: string;
}
function filenameFromPath(filePath: string) {
return filePath.split(/[\\/]/).pop() || `upload-${Date.now()}`;
}
async function uploadManagedAdminFile(
filePath: string,
scene: AdminUploadScene,
fallbackUrl: string,
meta: AdminDirectUploadMeta = {},
fallbackFormData: Record<string, string | number> = {},
) {
const policy = await request<AdminDirectUploadPolicy>("/api/admin/file-upload/direct-policy", {
method: "POST",
data: {
upload_scene: scene,
original_name: meta.original_name || filenameFromPath(filePath),
file_size: meta.file_size || 0,
mime_type: meta.mime_type || "",
},
});
const formData = { ...fallbackFormData, upload_scene: scene };
if (!policy.enabled) {
return uploadFile<AdminFileAsset>(fallbackUrl, filePath, formData);
}
if (!policy.upload_url || !policy.form_data || !policy.asset) {
throw new Error("OSS 上传签名无效,请稍后重试");
}
await uploadDirectFile(policy.upload_url, filePath, policy.form_data);
return policy.asset;
}
export interface PaginatedList<T> {
list: T[];
total?: number;
page?: number;
page_size?: number;
}
export interface AdminOrderListItem {
id: number;
order_no: string;
appraisal_no: string;
product_name: string;
category_name: string;
brand_name: string;
service_provider: string;
service_provider_text: string;
source_channel: string;
source_channel_text: string;
source_customer_id: string;
order_status: string;
display_status: string;
internal_tag_no?: string;
warehouse_bucket?: string;
warehouse_bucket_text?: string;
estimated_finish_time: string;
pay_amount: number;
created_at: string;
}
export interface AdminManualOrderMaterialItem {
item_code: string;
item_name: string;
is_required: boolean;
files: AdminFileAsset[];
}
export interface AdminManualOrderCreatePayload {
service_provider: string;
product_info: {
category_id: number;
brand_id: number;
brand_name: string;
product_name: string;
color: string;
size_spec: string;
serial_no: string;
};
extra_info: {
purchase_channel: string;
purchase_price: number;
usage_status: string;
condition_desc: string;
remark: string;
};
return_address: {
consignee: string;
mobile: string;
province: string;
city: string;
district: string;
detail_address: string;
};
materials: AdminManualOrderMaterialItem[];
}
export interface AdminManualOrderCreateResponse {
order_id: number;
order_no: string;
appraisal_no: string;
user_id: number;
next_status: "pending_shipping";
}
export interface AdminManualOrderMeta {
categories: Array<{
id: number;
name: string;
code: string;
supported_service_types: string[];
}>;
brands: Array<{
id: number;
name: string;
en_name: string;
code: string;
category_ids: number[];
supported_service_types: string[];
}>;
}
export interface AdminOrderDetail {
order_info: AdminOrderListItem & {
can_mark_received: boolean;
can_submit_return_logistics: boolean;
return_logistics_block_reason: string;
};
product_info: {
product_name: string;
category_name: string;
brand_name: string;
color: string;
size_spec: string;
serial_no: string;
};
extra_info: Record<string, any>;
shipping_target: null | Record<string, any>;
return_address: null | {
consignee: string;
mobile: string;
full_address: string;
};
logistics_info: null | Record<string, any>;
inbound_attachments: AdminFileAsset[];
transfer_flow: null | {
internal_tag_no: string;
};
return_logistics: null | Record<string, any>;
supplement_task: null | Record<string, any>;
report_summary: null | {
id?: number;
report_no: string;
report_title: string;
report_status: string;
report_status_text?: string;
publish_time: string;
};
timeline: Array<{
node_text: string;
node_desc: string;
occurred_at: string;
}>;
}
export interface AdminWarehouseWorkbenchContext {
order_info: {
id: number;
order_no: string;
appraisal_no: string;
service_provider: string;
service_provider_text: string;
source_channel: string;
source_channel_text: string;
source_customer_id: string;
order_status: string;
display_status: string;
};
product_info: {
product_name: string;
category_name: string;
brand_name: string;
color: string;
size_spec: string;
serial_no: string;
};
logistics_info: null | {
express_company: string;
tracking_no: string;
tracking_status: string;
};
return_address: null | {
consignee: string;
mobile: string;
full_address: string;
};
return_logistics: null | {
express_company: string;
tracking_no: string;
tracking_status: string;
};
transfer_flow: null | {
id?: number;
internal_tag_no: string;
flow_status?: string;
current_stage: string;
current_stage_text: string;
current_location: string;
current_location_text: string;
return_confirmed_at?: string;
return_shipped_at?: string;
};
report_info: null | {
id: number;
report_no: string;
report_status: string;
publish_time: string;
zhongjian_report_no: string;
zhongjian_report_files: AdminFileAsset[];
};
flow_logs?: Array<{
id: number;
action_text: string;
operator_name: string;
remark: string;
created_at: string;
inbound_attachments?: AdminFileAsset[];
packing_attachments?: AdminFileAsset[];
}>;
return_verification?: {
verified: boolean;
report_id: number;
report_no: string;
};
next_action?: string;
next_action_text?: string;
}
export interface AdminAppraisalTaskListItem {
id: number;
order_id: number;
order_no: string;
appraisal_no: string;
external_order_no: string;
service_provider: string;
service_provider_text: string;
task_stage: string;
task_stage_text: string;
status: string;
status_text: string;
assignee_id: number;
product_name: string;
category_name: string;
brand_name: string;
assignee_name: string;
result_text: string;
started_at: string;
submitted_at: string;
sla_deadline: string;
is_overtime: boolean;
display_status: string;
internal_tag_no?: string;
}
export interface AdminAppraisalTaskDetail {
task_info: AdminAppraisalTaskListItem & {
is_overtime: boolean;
};
report_summary: null | {
id: number;
report_no: string;
report_status: string;
report_status_text: string;
};
material_tag?: null | Record<string, any>;
product_info: {
product_name: string;
category_id: number;
category_name: string;
brand_id: number;
brand_name: string;
color: string;
size_spec: string;
serial_no: string;
};
extra_info: Record<string, any>;
result_info: {
result_text: string;
result_desc: string;
condition_grade: string;
condition_desc?: string;
valuation_min: number;
valuation_max: number;
valuation_desc?: string;
attachments: AdminFileAsset[];
external_remark: string;
internal_remark: string;
key_points: Array<{
point_code: string;
point_name: string;
point_value: string;
point_remark: string;
}>;
};
prefill_result_info?: null | (AdminAppraisalTaskDetail["result_info"] & {
source_task_id?: number;
source_stage?: string;
source_stage_text?: string;
});
appraisal_template: null | {
id?: number;
name?: string;
code?: string;
service_provider?: string;
service_provider_text?: string;
result_options: string[];
condition_options: string[];
valuation_hint?: string;
key_points: Array<{
point_code: string;
point_name: string;
point_type: "text" | "textarea" | "select" | "boolean";
options: string[];
sort_order?: number;
is_required: boolean;
point_value: string;
point_remark: string;
}>;
};
stage_tasks?: Array<AdminAppraisalTaskListItem & { is_current?: boolean }>;
timeline: Array<{
node_text: string;
node_desc: string;
occurred_at: string;
}>;
materials: Array<{
item_name: string;
status: string;
source_type: string;
files: Array<{
file_id: string;
file_url: string;
thumbnail_url: string;
}>;
}>;
supplement_task: null | {
id: number;
reason: string;
deadline: string;
status: string;
items: Array<{
item_name: string;
guide_text: string;
is_required: boolean;
}>;
};
zhongjian_report: {
report_no: string;
files: AdminFileAsset[];
};
}
export interface AdminReportListItem {
id: number;
order_id: number;
order_no: string;
appraisal_no: string;
report_no: string;
report_type: string;
report_type_text: string;
report_title: string;
report_status: string;
report_status_text: string;
service_provider: string;
service_provider_text: string;
institution_name: string;
publish_time: string;
zhongjian_report_no: string;
report_entry_admin_name: string;
report_entered_at: string;
product_name: string;
category_name: string;
brand_name: string;
}
export interface AdminReportDetail {
report_header: Partial<AdminReportListItem> & {
id: number;
order_id: number;
report_no: string;
report_type: string;
report_type_text: string;
report_title: string;
report_status: string;
report_status_text: string;
service_provider: string;
service_provider_text: string;
institution_name: string;
publish_time: string;
zhongjian_report_no: string;
report_entry_admin_id: number;
report_entry_admin_name: string;
report_entered_at: string;
};
product_info: Record<string, any>;
result_info: Record<string, any>;
appraisal_info: Record<string, any>;
valuation_info: Record<string, any>;
evidence_attachments: AdminFileAsset[];
zhongjian_report_files: AdminFileAsset[];
risk_notice_text: string;
verify_info: {
verify_status: string;
verify_url: string;
verify_qrcode_url: string;
report_page_url: string;
verify_count: number;
};
}
export const adminApi = {
login(mobile: string, password: string) {
return request<AdminLoginResponse>("/api/admin/auth/login", {
method: "POST",
data: { mobile, password },
});
},
getAuthMe() {
return request<{ admin_info: AdminSessionInfo }>("/api/admin/auth/me");
},
logout() {
return request<Record<string, never>>("/api/admin/auth/logout", { method: "POST" });
},
getOrders(params?: Record<string, string | number>) {
return request<PaginatedList<AdminOrderListItem>>("/api/admin/orders", { params });
},
getOrderDetail(id: number) {
return request<AdminOrderDetail>("/api/admin/order/detail", { params: { id } });
},
getManualOrderMeta() {
return request<AdminManualOrderMeta>("/api/admin/manual-order/meta");
},
getExpressCompanies(params: { enabled_only?: 0 | 1 } = { enabled_only: 1 }) {
return request<{ list: AdminExpressCompanyItem[]; default_company: string }>("/api/admin/express-companies", { params });
},
createManualOrder(data: AdminManualOrderCreatePayload) {
return request<AdminManualOrderCreateResponse>("/api/admin/manual-order/create", {
method: "POST",
data: data as unknown as Record<string, unknown>,
});
},
uploadManualOrderFile(filePath: string) {
return uploadFile<AdminFileAsset>("/api/admin/manual-order/file/upload", filePath);
},
lookupWarehouseInbound(inboundNo: string) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/inbound/lookup", {
params: { inbound_no: inboundNo },
});
},
receiveWarehouseInbound(data: { inbound_no: string; internal_tag_no: string; inbound_attachments?: AdminFileAsset[] }) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/inbound/receive", {
method: "POST",
data,
});
},
uploadWarehouseInboundEvidenceFile(filePath: string, meta: AdminDirectUploadMeta = {}) {
return uploadManagedAdminFile(
filePath,
"warehouse_inbound_evidence",
"/api/admin/warehouse-workbench/inbound/evidence/upload",
meta,
);
},
lookupZhongjianWarehouseTransfer(internalTagNo: string) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/zhongjian/lookup", {
params: { internal_tag_no: internalTagNo },
});
},
zhongjianWarehouseOutbound(internalTagNo: string) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/zhongjian/outbound", {
method: "POST",
data: { internal_tag_no: internalTagNo },
});
},
zhongjianWarehouseInbound(internalTagNo: string) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/zhongjian/inbound", {
method: "POST",
data: { internal_tag_no: internalTagNo },
});
},
lookupWarehouseReturn(internalTagNo: string) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/return/lookup", {
params: { internal_tag_no: internalTagNo },
});
},
verifyWarehouseReturnMaterialTag(data: { internal_tag_no: string; qr_input: string }) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/return/material-tag/verify", {
method: "POST",
data,
});
},
confirmWarehouseReturnReport(data: { internal_tag_no: string; report_id: number }) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/return/report/confirm", {
method: "POST",
data,
});
},
confirmWarehouseReturnZhongjian(internalTagNo: string) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/return/zhongjian/confirm", {
method: "POST",
data: { internal_tag_no: internalTagNo },
});
},
uploadWarehouseReturnPackingFile(filePath: string, meta: AdminDirectUploadMeta = {}) {
return uploadManagedAdminFile(
filePath,
"warehouse_return_packing",
"/api/admin/warehouse-workbench/return/packing/upload",
meta,
);
},
shipWarehouseReturn(data: { internal_tag_no: string; express_company: string; tracking_no: string; packing_attachments?: AdminFileAsset[] }) {
return request<AdminWarehouseWorkbenchContext>("/api/admin/warehouse-workbench/return/ship", {
method: "POST",
data,
});
},
getAppraisalTasks(params?: Record<string, string | number>) {
return request<PaginatedList<AdminAppraisalTaskListItem>>("/api/admin/appraisal-tasks", { params });
},
getAppraisalTaskDetail(id: number) {
return request<AdminAppraisalTaskDetail>("/api/admin/appraisal-task/detail", { params: { id } });
},
scanAppraisalTransferTag(internalTagNo: string) {
return request<{ task_id: number; order_id: number; service_provider: string; service_provider_text: string }>(
"/api/admin/appraisal-task/transfer-tag/scan",
{ method: "POST", data: { internal_tag_no: internalTagNo } },
);
},
saveAppraisalTaskResult(data: Record<string, unknown>) {
return request<{ id: number }>("/api/admin/appraisal-task/save-result", { method: "POST", data });
},
requestAppraisalTaskSupplement(data: Record<string, unknown>) {
return request<{ id: number; supplement_task_id: number }>("/api/admin/appraisal-task/request-supplement", {
method: "POST",
data,
});
},
saveZhongjianAppraisalReport(data: Record<string, unknown>) {
return request<{ id: number; report: Record<string, any> }>("/api/admin/appraisal-task/zhongjian-report/save", {
method: "POST",
data,
});
},
publishAppraisalTaskWithMaterialTag(data: { id: number; qr_input: string }) {
return request<Record<string, any>>("/api/admin/appraisal-task/material-tag/publish", {
method: "POST",
data,
});
},
uploadAppraisalEvidenceFile(
filePath: string,
taskId?: number,
meta: AdminDirectUploadMeta = {},
scene: AdminUploadScene = "appraisal_evidence",
) {
const formData: Record<string, string | number> = taskId ? { task_id: taskId } : {};
return uploadManagedAdminFile(filePath, scene, "/api/admin/appraisal-task/evidence/upload", meta, formData);
},
deleteAppraisalEvidenceFile(fileUrl: string, taskId?: number) {
return request<{ file_url: string }>("/api/admin/appraisal-task/evidence/delete", {
method: "POST",
data: { file_url: fileUrl, ...(taskId ? { task_id: taskId } : {}) },
});
},
getReports(params?: Record<string, string | number>) {
return request<PaginatedList<AdminReportListItem>>("/api/admin/reports", { params });
},
getReportDetail(id: number) {
return request<AdminReportDetail>("/api/admin/report/detail", { params: { id } });
},
};