2026-08-14 10:19:44 +08:00
|
|
|
|
import api from "./api";
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// 效能分析看板 — 前后端数据契约类型 + API
|
|
|
|
|
|
// 对应后端 app/services/analytics_service.py 的 Pydantic Schema
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
// ─── 个人能力图谱(单机颗粒度分组柱状图) ──────────────────
|
|
|
|
|
|
export interface CapabilityDataPoint {
|
|
|
|
|
|
value: number | null; // 该人员在该设备上的总耗时(未触及为 null,真实 0 为 0)
|
|
|
|
|
|
spec_model: string; // 规格型号
|
|
|
|
|
|
status: string; // 该设备当前状态 WIP/PENDING/COMPLETED/—
|
|
|
|
|
|
first_received_at: string; // 最早接收时间 YYYY-MM-DD HH:mm
|
|
|
|
|
|
last_completed_at: string; // 最后完成时间 YYYY-MM-DD HH:mm(无则空串)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface CapabilityDevice {
|
|
|
|
|
|
product_sn: string; // 身份证
|
|
|
|
|
|
external_serial: string | null; // 产品序列号(业务序列号)
|
|
|
|
|
|
spec_model: string;
|
2026-08-14 15:43:22 +08:00
|
|
|
|
material_name: string; // 物料名称
|
2026-08-14 10:19:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface CapabilitySeries {
|
|
|
|
|
|
name: string; // 人员姓名
|
|
|
|
|
|
assignee_id: string; // 人员ID
|
|
|
|
|
|
data: CapabilityDataPoint[]; // 与 categories 严格对齐,未触及设备补 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface CapabilityResponse {
|
|
|
|
|
|
categories: string[]; // X 轴:设备身份证(按时间升序)
|
|
|
|
|
|
devices: CapabilityDevice[]; // 与 categories 对齐的设备元数据
|
|
|
|
|
|
series: CapabilitySeries[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─── 设备流转对比(堆叠柱状) ──────────────────────────────
|
|
|
|
|
|
export interface FlowDevice {
|
|
|
|
|
|
product_sn: string;
|
|
|
|
|
|
external_serial: string | null;
|
|
|
|
|
|
material_name: string;
|
|
|
|
|
|
spec_model: string;
|
2026-08-14 11:44:48 +08:00
|
|
|
|
lead_time: number; // 设备生命周期总时长(小时)
|
|
|
|
|
|
started_at: string; // 设备最早介入时间(T0),MM-DD HH:mm
|
2026-08-14 10:19:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-14 11:44:48 +08:00
|
|
|
|
// 时间区间:deviceIndex, startOffset, endOffset, taskName, duration, isMain
|
|
|
|
|
|
export type FlowInterval = [number, number, number, string, number, number];
|
|
|
|
|
|
|
2026-08-14 10:19:44 +08:00
|
|
|
|
export interface FlowSeries {
|
2026-08-14 11:44:48 +08:00
|
|
|
|
name: string; // 人员姓名
|
|
|
|
|
|
data: FlowInterval[]; // 该人员的任务时间区间列表(同一设备可多次出现)
|
2026-08-14 10:19:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface FlowResponse {
|
|
|
|
|
|
devices: FlowDevice[];
|
|
|
|
|
|
series: FlowSeries[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─── 设备备注记录(弹窗下钻) ──────────────────────────────
|
|
|
|
|
|
export interface DeviceRecord {
|
|
|
|
|
|
task_name: string; // 工序名
|
|
|
|
|
|
assignee_name: string; // 负责人姓名
|
|
|
|
|
|
status: string; // 任务状态
|
|
|
|
|
|
remark: string | null; // 备注
|
|
|
|
|
|
images: string[]; // 图片 URL 列表
|
|
|
|
|
|
created_at: string; // 记录时间 ISO
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─── 顶部下拉选项 ──────────────────────────────────────────
|
|
|
|
|
|
export interface AssigneeOption {
|
|
|
|
|
|
id: string;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-14 14:30:35 +08:00
|
|
|
|
export interface SpecModelOption {
|
|
|
|
|
|
spec_model: string;
|
|
|
|
|
|
material_name: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface DeviceOption {
|
|
|
|
|
|
product_sn: string;
|
|
|
|
|
|
external_serial: string | null;
|
|
|
|
|
|
material_name: string;
|
|
|
|
|
|
spec_model: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-14 10:19:44 +08:00
|
|
|
|
export interface AnalyticsOptions {
|
|
|
|
|
|
assignees: AssigneeOption[];
|
2026-08-14 14:30:35 +08:00
|
|
|
|
spec_models: SpecModelOption[];
|
|
|
|
|
|
devices: DeviceOption[];
|
2026-08-14 10:19:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─── 查询参数 ──────────────────────────────────────────────
|
|
|
|
|
|
export interface CapabilityQuery {
|
|
|
|
|
|
assignee_ids?: string[];
|
|
|
|
|
|
spec_models?: string[];
|
|
|
|
|
|
since?: string;
|
|
|
|
|
|
until?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface FlowQuery {
|
|
|
|
|
|
product_sns?: string[];
|
|
|
|
|
|
spec_models?: string[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
// API 方法
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
|
|
|
|
|
|
|
export async function fetchCapabilityProfile(query: CapabilityQuery): Promise<CapabilityResponse> {
|
|
|
|
|
|
const params: Record<string, string> = {};
|
|
|
|
|
|
if (query.assignee_ids?.length) params.assignee_ids = query.assignee_ids.join(",");
|
|
|
|
|
|
if (query.spec_models?.length) params.spec_models = query.spec_models.join(",");
|
|
|
|
|
|
if (query.since) params.since = query.since;
|
|
|
|
|
|
if (query.until) params.until = query.until;
|
|
|
|
|
|
const { data } = await api.get<CapabilityResponse>("/analytics/capability", { params });
|
|
|
|
|
|
return data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function fetchFlowData(query: FlowQuery): Promise<FlowResponse> {
|
|
|
|
|
|
const params: Record<string, string> = {};
|
|
|
|
|
|
if (query.product_sns?.length) params.product_sns = query.product_sns.join(",");
|
|
|
|
|
|
if (query.spec_models?.length) params.spec_models = query.spec_models.join(",");
|
|
|
|
|
|
const { data } = await api.get<FlowResponse>("/analytics/flow", { params });
|
|
|
|
|
|
return data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function fetchDeviceRecords(product_sn: string, assigneeIds?: string[]): Promise<DeviceRecord[]> {
|
|
|
|
|
|
const params: Record<string, string> = { product_sn };
|
|
|
|
|
|
if (assigneeIds?.length) params.assignee_ids = assigneeIds.join(",");
|
|
|
|
|
|
const { data } = await api.get<DeviceRecord[]>("/analytics/device-records", { params });
|
|
|
|
|
|
return data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function fetchAnalyticsOptions(assigneeIds?: string[], specModels?: string[]): Promise<AnalyticsOptions> {
|
|
|
|
|
|
const params: Record<string, string> = {};
|
|
|
|
|
|
if (assigneeIds?.length) params.assignee_ids = assigneeIds.join(",");
|
|
|
|
|
|
if (specModels?.length) params.spec_models = specModels.join(",");
|
|
|
|
|
|
const { data } = await api.get<AnalyticsOptions>("/analytics/options", { params });
|
|
|
|
|
|
return data;
|
|
|
|
|
|
}
|