feat: 新增效能分析看板(个人能力图谱 + 设备人员耗时对比)
- 前端:AnalyticsDashboard 页面 + BaseEChart 封装 + analyticsApi,路由与导航 - 后端:/analytics 系列接口(capability/flow/options/device-records) - 能力图谱单机颗粒度、流转对比按人堆叠识别瓶颈、点击下钻备注、筛选动态联动 - 依赖:引入 echarts,移除 echarts-for-react
This commit is contained in:
122
frontend/src/services/analyticsApi.ts
Normal file
122
frontend/src/services/analyticsApi.ts
Normal file
@ -0,0 +1,122 @@
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export interface FlowSeries {
|
||||
name: string; // 工序节点名
|
||||
data: (number | null)[]; // 每台设备在该工序的总耗时(未经过为 null)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export interface AnalyticsOptions {
|
||||
assignees: AssigneeOption[];
|
||||
spec_models: string[];
|
||||
}
|
||||
|
||||
// ─── 查询参数 ──────────────────────────────────────────────
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user