feat: build collaboration workspaces
This commit is contained in:
200
modules/devices/types.ts
Normal file
200
modules/devices/types.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
export const DEVICE_ASSET_STATUS_VALUES = ["active", "maintenance", "disabled", "retired"] as const;
|
||||
export type DeviceAssetStatus = (typeof DEVICE_ASSET_STATUS_VALUES)[number];
|
||||
|
||||
export const MAINTENANCE_TICKET_STATUS_VALUES = ["open", "assigned", "resolved", "closed", "cancelled"] as const;
|
||||
export type MaintenanceTicketStatus = (typeof MAINTENANCE_TICKET_STATUS_VALUES)[number];
|
||||
|
||||
export const MAINTENANCE_TICKET_PRIORITY_VALUES = ["low", "normal", "high", "urgent"] as const;
|
||||
export type MaintenanceTicketPriority = (typeof MAINTENANCE_TICKET_PRIORITY_VALUES)[number];
|
||||
|
||||
export const DEVICE_ASSET_STATUS_LABELS: Record<DeviceAssetStatus, string> = {
|
||||
active: "运行中",
|
||||
maintenance: "维护中",
|
||||
disabled: "停用",
|
||||
retired: "已退役",
|
||||
};
|
||||
|
||||
export const MAINTENANCE_TICKET_STATUS_LABELS: Record<MaintenanceTicketStatus, string> = {
|
||||
open: "待处理",
|
||||
assigned: "已派单",
|
||||
resolved: "已解决",
|
||||
closed: "已关闭",
|
||||
cancelled: "已取消",
|
||||
};
|
||||
|
||||
export const MAINTENANCE_TICKET_PRIORITY_LABELS: Record<MaintenanceTicketPriority, string> = {
|
||||
low: "低",
|
||||
normal: "普通",
|
||||
high: "高",
|
||||
urgent: "紧急",
|
||||
};
|
||||
|
||||
export type DeviceAsset = {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
code: string;
|
||||
category: string;
|
||||
location: string;
|
||||
status: DeviceAssetStatus;
|
||||
lastInspectedAt?: string;
|
||||
notes: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type MaintenanceTicket = {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
deviceId?: string;
|
||||
deviceName: string;
|
||||
title: string;
|
||||
description: string;
|
||||
priority: MaintenanceTicketPriority;
|
||||
status: MaintenanceTicketStatus;
|
||||
assigneeLabel: string;
|
||||
resolutionNotes: string;
|
||||
resolvedAt?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type DeviceOperationsData = {
|
||||
metrics: {
|
||||
activeDevices: number;
|
||||
maintenanceDevices: number;
|
||||
openTickets: number;
|
||||
urgentTickets: number;
|
||||
};
|
||||
devices: DeviceAsset[];
|
||||
tickets: MaintenanceTicket[];
|
||||
};
|
||||
|
||||
export type DeviceAssetInput = {
|
||||
name: string;
|
||||
code: string;
|
||||
category: string;
|
||||
location: string;
|
||||
status: DeviceAssetStatus;
|
||||
lastInspectedAt?: string;
|
||||
notes: string;
|
||||
};
|
||||
|
||||
export type MaintenanceTicketInput = {
|
||||
deviceId?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
priority: MaintenanceTicketPriority;
|
||||
status: MaintenanceTicketStatus;
|
||||
assigneeLabel: string;
|
||||
resolutionNotes: string;
|
||||
};
|
||||
|
||||
type ValidationSuccess<T> = {
|
||||
success: true;
|
||||
data: T;
|
||||
};
|
||||
|
||||
type ValidationFailure = {
|
||||
success: false;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
export type ValidationResult<T> = ValidationSuccess<T> | ValidationFailure;
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function readString(source: Record<string, unknown>, key: string): string {
|
||||
const value = source[key];
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
}
|
||||
|
||||
function readOptionalString(source: Record<string, unknown>, key: string): string | undefined {
|
||||
const value = readString(source, key);
|
||||
return value || undefined;
|
||||
}
|
||||
|
||||
function readEnum<T extends string>(value: unknown, values: readonly T[]): T | null {
|
||||
return typeof value === "string" ? values.find((item) => item === value) ?? null : null;
|
||||
}
|
||||
|
||||
function validateIsoDate(value: string | undefined, label: string): ValidationResult<string | undefined> {
|
||||
if (!value) {
|
||||
return { success: true, data: undefined };
|
||||
}
|
||||
|
||||
return Number.isNaN(new Date(value).getTime())
|
||||
? { success: false, reason: `${label}无效` }
|
||||
: { success: true, data: value };
|
||||
}
|
||||
|
||||
export function validateDeviceAssetInput(value: unknown): ValidationResult<DeviceAssetInput> {
|
||||
if (!isRecord(value)) {
|
||||
return { success: false, reason: "请求数据格式无效" };
|
||||
}
|
||||
|
||||
const name = readString(value, "name");
|
||||
const code = readString(value, "code");
|
||||
if (!name || !code) {
|
||||
return { success: false, reason: "设备名称和编号不能为空" };
|
||||
}
|
||||
|
||||
const status = readEnum(value.status, DEVICE_ASSET_STATUS_VALUES);
|
||||
if (!status) {
|
||||
return { success: false, reason: "设备状态无效" };
|
||||
}
|
||||
|
||||
const lastInspectedAt = validateIsoDate(readOptionalString(value, "lastInspectedAt"), "最近巡检时间");
|
||||
if (!lastInspectedAt.success) {
|
||||
return lastInspectedAt;
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
name,
|
||||
code,
|
||||
category: readString(value, "category"),
|
||||
location: readString(value, "location"),
|
||||
status,
|
||||
lastInspectedAt: lastInspectedAt.data,
|
||||
notes: readString(value, "notes"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function validateMaintenanceTicketInput(value: unknown): ValidationResult<MaintenanceTicketInput> {
|
||||
if (!isRecord(value)) {
|
||||
return { success: false, reason: "请求数据格式无效" };
|
||||
}
|
||||
|
||||
const title = readString(value, "title");
|
||||
if (!title) {
|
||||
return { success: false, reason: "工单标题不能为空" };
|
||||
}
|
||||
|
||||
const priority = readEnum(value.priority, MAINTENANCE_TICKET_PRIORITY_VALUES);
|
||||
if (!priority) {
|
||||
return { success: false, reason: "工单优先级无效" };
|
||||
}
|
||||
|
||||
const status = readEnum(value.status, MAINTENANCE_TICKET_STATUS_VALUES);
|
||||
if (!status) {
|
||||
return { success: false, reason: "工单状态无效" };
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
deviceId: readOptionalString(value, "deviceId"),
|
||||
title,
|
||||
description: readString(value, "description"),
|
||||
priority,
|
||||
status,
|
||||
assigneeLabel: readString(value, "assigneeLabel"),
|
||||
resolutionNotes: readString(value, "resolutionNotes"),
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user