631 lines
18 KiB
TypeScript
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 } });
|
|
},
|
|
};
|