refactor(workbench): simplify appointment tasks

This commit is contained in:
2026-09-24 12:01:11 +08:00
parent 436d5500f1
commit ddf953b641
28 changed files with 443 additions and 1384 deletions
@@ -46,14 +46,11 @@ import {
createStatusFilterOptions,
createTaskFilterOptions,
formatTime,
getConditionTime,
getStatusActivity,
getStatusIcon,
getStatusTone,
getWorkOrderCurrentStage,
getWorkOrderStageActivity,
getWorkOrderStageTone,
groupScheduledConditions,
sortConditionsNewestFirst,
type ConditionStatusFilterOption,
type ConditionStatusFilterValue,
type ConditionTaskFilterOption,
@@ -171,10 +168,6 @@ export function ScheduledConditionFeed({
() => groupScheduledConditions(categoryConditions),
[categoryConditions]
);
const allTimelineConditions = useMemo(
() => [...allRecentConditions, ...allFutureWorkOrders],
[allFutureWorkOrders, allRecentConditions]
);
const taskFilterOptions = useMemo(
() => createTaskFilterOptions(categoryConditions),
[categoryConditions]
@@ -203,8 +196,10 @@ export function ScheduledConditionFeed({
[filteredConditions]
);
const timelineConditions = useMemo(
() => [...recentConditions, ...futureWorkOrders],
[futureWorkOrders, recentConditions]
() => taskCategory === "appointment"
? sortConditionsNewestFirst([...recentConditions, ...futureWorkOrders])
: [...recentConditions, ...futureWorkOrders],
[futureWorkOrders, recentConditions, taskCategory]
);
const filterActive = taskFilter !== CONDITION_FILTER_ALL || statusFilter !== CONDITION_FILTER_ALL;
const totalConditionCount = allRecentConditions.length + allFutureWorkOrders.length;
@@ -214,8 +209,7 @@ export function ScheduledConditionFeed({
: `定时 ${conditionsByCategory.scheduled.length} · 调查 ${conditionsByCategory.investigation.length} · 预约 ${conditionsByCategory.appointment.length}`;
const selectedCondition =
timelineConditions.find((condition) => condition.id === selectedConditionId) ??
recentConditions[0] ??
futureWorkOrders[0] ??
timelineConditions[0] ??
null;
const focusConditionId = focusRequest?.conditionId;
const focusRequestId = focusRequest?.requestId;
@@ -294,7 +288,7 @@ export function ScheduledConditionFeed({
function handleToggleExpanded() {
updateExpanded(!expanded);
updateSelectedConditionId(
selectedConditionId ?? recentConditions[0]?.id ?? futureWorkOrders[0]?.id ?? null
selectedConditionId ?? timelineConditions[0]?.id ?? null
);
}
@@ -303,7 +297,9 @@ export function ScheduledConditionFeed({
if (nextCategory !== "scheduled") setScheduleOpen(false);
setTaskFilter(CONDITION_FILTER_ALL);
setStatusFilter(CONDITION_FILTER_ALL);
updateSelectedConditionId(conditionsByCategory[nextCategory][0]?.id ?? null);
updateSelectedConditionId(
sortConditionsNewestFirst(conditionsByCategory[nextCategory])[0]?.id ?? null
);
}
function handleToggleSchedule() {
@@ -562,19 +558,21 @@ export function ScheduledConditionFeed({
<ConditionTimelinePanel
expanded={expanded}
presentation={presentation}
loading={activeLoading}
emptyTitle={
backendError && taskCategory !== "scheduled"
? `${WORKBENCH_TASK_CATEGORIES.find((item) => item.id === taskCategory)?.label ?? "后端任务"}暂不可用`
: undefined
}
emptyDescription={
backendError && taskCategory !== "scheduled"
? backendError
: undefined
}
taskCategory={taskCategory}
loading={activeLoading}
emptyTitle={
backendError && taskCategory !== "scheduled"
? `${WORKBENCH_TASK_CATEGORIES.find((item) => item.id === taskCategory)?.label ?? "后端任务"}暂不可用`
: undefined
}
emptyDescription={
backendError && taskCategory !== "scheduled"
? backendError
: undefined
}
recentConditions={recentConditions}
futureWorkOrders={futureWorkOrders}
timelineConditions={timelineConditions}
taskFilter={taskFilter}
statusFilter={statusFilter}
taskFilterOptions={taskFilterOptions}
@@ -648,9 +646,11 @@ function formatLocalDateTimeInput(value: Date) {
type ConditionTimelinePanelProps = {
expanded: boolean;
presentation: ScheduledConditionFeedPresentation;
taskCategory: WorkbenchTaskCategory;
loading: boolean;
recentConditions: ScheduledConditionItem[];
futureWorkOrders: ScheduledConditionItem[];
timelineConditions: ScheduledConditionItem[];
taskFilter: ConditionTaskFilterValue;
statusFilter: ConditionStatusFilterValue;
taskFilterOptions: ConditionTaskFilterOption[];
@@ -670,9 +670,11 @@ type ConditionTimelinePanelProps = {
function ConditionTimelinePanel({
expanded,
presentation,
taskCategory,
loading,
recentConditions,
futureWorkOrders,
timelineConditions,
taskFilter,
statusFilter,
taskFilterOptions,
@@ -689,6 +691,7 @@ function ConditionTimelinePanel({
onSelectCondition
}: ConditionTimelinePanelProps) {
const filterActive = taskFilter !== CONDITION_FILTER_ALL || statusFilter !== CONDITION_FILTER_ALL;
const mainConditions = taskCategory === "appointment" ? timelineConditions : recentConditions;
return (
<section
@@ -718,7 +721,10 @@ function ConditionTimelinePanel({
onResetFilters={onResetFilters}
/>
) : null}
{(expanded || presentation === "mobile-sheet") && !loading && futureWorkOrders.length > 0 ? (
{taskCategory !== "appointment"
&& (expanded || presentation === "mobile-sheet")
&& !loading
&& futureWorkOrders.length > 0 ? (
<section className="mb-2">
<ConditionGroupHeader
icon={ClipboardList}
@@ -736,16 +742,16 @@ function ConditionTimelinePanel({
</section>
) : null}
<ConditionGroupHeader
icon={History}
icon={taskCategory === "appointment" ? ClipboardList : History}
title="最近工况"
count={loading ? 0 : recentConditions.length}
count={loading ? 0 : mainConditions.length}
/>
<div className="scheduled-feed-scroll -mr-2 min-h-0 flex-1 overflow-y-auto pb-4 pl-0.5 pr-2 pt-0.5">
{loading ? (
<ConditionTimelineSkeleton rows={expanded ? 7 : 6} />
) : recentConditions.length > 0 ? (
) : mainConditions.length > 0 ? (
<ConditionRows
conditions={recentConditions}
conditions={mainConditions}
selectedConditionId={selectedConditionId}
onSelectCondition={onSelectCondition}
/>
@@ -1078,18 +1084,8 @@ function ConditionTimelineRow({
onSelect
}: ConditionTimelineRowProps) {
const Icon = getStatusIcon(condition.status);
const isWorkOrder = condition.kind === "work_order";
const workOrderStage = isWorkOrder ? getWorkOrderCurrentStage(condition)?.status : undefined;
const tone = isWorkOrder
? condition.status === "running"
? getWorkOrderStageTone(workOrderStage)
: getStatusTone(condition.status)
: getStatusTone(condition.status);
const activity = isWorkOrder
? condition.status === "running"
? getWorkOrderStageActivity(workOrderStage)
: getStatusActivity(condition.status)
: getStatusActivity(condition.status);
const tone = getStatusTone(condition.status);
const activity = getStatusActivity(condition.status);
return (
<button