feat: initialize TJWater WebGIS frontend

This commit is contained in:
2026-07-21 18:31:08 +08:00
commit ad5e5d3133
191 changed files with 37963 additions and 0 deletions
@@ -0,0 +1,175 @@
import {
AlertTriangle,
CheckCircle2,
Clock3,
Loader2,
XCircle
} from "lucide-react";
import type {
ScheduledConditionItem,
ScheduledConditionStatus,
ScheduledWorkOrderItem,
ScheduledWorkOrderStage
} from "@/features/workbench/types";
export const CONDITION_FILTER_ALL = "__all__";
export const statusLabels: Record<ScheduledConditionStatus, string> = {
completed: "完成",
running: "执行中",
warning: "关注",
error: "异常",
pending: "预约"
};
export const statusClassNames: Record<ScheduledConditionStatus, string> = {
completed: "border-green-100 bg-green-50 text-green-700",
running: "border-blue-100 bg-blue-50 text-blue-700",
warning: "border-orange-100 bg-orange-50 text-orange-700",
error: "border-red-100 bg-red-50 text-red-700",
pending: "border-slate-200 bg-slate-100 text-slate-600"
};
const statusIcons: Record<ScheduledConditionStatus, typeof CheckCircle2> = {
completed: CheckCircle2,
running: Loader2,
warning: AlertTriangle,
error: XCircle,
pending: Clock3
};
const statusIconClassNames: Record<ScheduledConditionStatus, string> = {
completed: "bg-green-50 text-green-700",
running: "bg-blue-50 text-blue-700",
warning: "bg-orange-50 text-orange-700",
error: "bg-red-50 text-red-700",
pending: "bg-slate-100 text-slate-600"
};
const conditionStatusOrder: ScheduledConditionStatus[] = ["running", "warning", "error", "completed", "pending"];
export type ConditionTaskFilterValue = typeof CONDITION_FILTER_ALL | string;
export type ConditionStatusFilterValue = typeof CONDITION_FILTER_ALL | ScheduledConditionStatus;
export type ConditionTaskFilterOption = {
value: ConditionTaskFilterValue;
label: string;
count: number;
};
export type ConditionStatusFilterOption = {
value: ScheduledConditionStatus;
label: string;
count: number;
};
export function groupScheduledConditions(conditions: ScheduledConditionItem[]) {
const recentConditions = conditions
.filter((condition) => condition.kind === "condition")
.sort((a, b) => getConditionTime(b) - getConditionTime(a));
const futureWorkOrders = conditions
.filter((condition) => condition.kind === "work_order")
.sort((a, b) => getConditionTime(a) - getConditionTime(b));
return { recentConditions, futureWorkOrders };
}
export function createTaskFilterOptions(conditions: ScheduledConditionItem[]): ConditionTaskFilterOption[] {
const taskCounts = new Map<string, number>();
conditions.forEach((condition) => {
taskCounts.set(condition.title, (taskCounts.get(condition.title) ?? 0) + 1);
});
return [...taskCounts.entries()]
.map(([label, count]) => ({ value: label, label, count }))
.sort((a, b) => b.count - a.count || a.label.localeCompare(b.label, "zh-CN"));
}
export function createStatusFilterOptions(conditions: ScheduledConditionItem[]): ConditionStatusFilterOption[] {
const statusCounts = new Map<ScheduledConditionStatus, number>();
conditions.forEach((condition) => {
statusCounts.set(condition.status, (statusCounts.get(condition.status) ?? 0) + 1);
});
return conditionStatusOrder.map((status) => ({
value: status,
label: statusLabels[status],
count: statusCounts.get(status) ?? 0
}));
}
export function getConditionTime(condition: ScheduledConditionItem) {
return Date.parse(condition.scheduledAt);
}
export function formatTime(value: string) {
const match = value.match(/T(\d{2}:\d{2})/);
return match?.[1] ?? value;
}
export function formatTimeRange(value: string, durationMinutes: number | undefined) {
const startTime = formatTime(value);
if (typeof durationMinutes !== "number") {
return startTime;
}
const endDate = new Date(Date.parse(value) + durationMinutes * 60_000);
const endTime = `${endDate.getHours().toString().padStart(2, "0")}:${endDate.getMinutes().toString().padStart(2, "0")}`;
return `${startTime} - ${endTime}`;
}
export function formatDuration(durationMinutes: number | undefined, status: ScheduledConditionStatus) {
if (status === "running") {
return "执行中";
}
if (typeof durationMinutes !== "number") {
return "未记录";
}
return `${durationMinutes} 分钟`;
}
export function getRiskLabel(riskLevel: ScheduledConditionItem["riskLevel"]) {
if (riskLevel === "critical") {
return "高风险";
}
if (riskLevel === "attention") {
return "关注";
}
return "正常";
}
export function getWorkOrderCurrentStage(condition: ScheduledWorkOrderItem) {
return (
condition.stages.find((stage) => stage.status === "current") ??
condition.stages.find((stage) => stage.status === "pending") ??
condition.stages.at(-1) ??
null
);
}
export function getWorkOrderStagePillClassName(stageId?: ScheduledWorkOrderStage["id"]) {
if (stageId === "execution") {
return "border-blue-100 bg-blue-50 text-blue-700";
}
if (stageId === "reply") {
return "border-green-100 bg-green-50 text-green-700";
}
return "border-indigo-100 bg-indigo-50 text-indigo-700";
}
export function getStatusIcon(status: ScheduledConditionStatus) {
return statusIcons[status];
}
export function getStatusIconClassName(status: ScheduledConditionStatus) {
return statusIconClassNames[status];
}