feat(qr): offline show_list диалог для QR-автоматизации КИПиА
- clientAutomationEngine: onShowTaskDialog callback для show_list - QrHandler: Dialog со списком найденных задач, навигация на /forms/11/tasks/:id
This commit is contained in:
@@ -208,6 +208,7 @@ export async function handleAutomationActions(
|
||||
deps: {
|
||||
toast: (opts: { title?: string; description?: string; variant?: 'default' | 'destructive' }) => void;
|
||||
navigate?: (path: string) => void;
|
||||
onShowTaskDialog?: (tasks: Array<{ id: number; title: string }>) => void;
|
||||
},
|
||||
): Promise<boolean> {
|
||||
const holder = extractActions(result);
|
||||
@@ -244,7 +245,11 @@ export async function handleAutomationActions(
|
||||
|
||||
if (holder.legacy) {
|
||||
handled = true;
|
||||
await handleLegacyAction(holder.legacy, deps);
|
||||
await handleLegacyAction(holder.legacy, {
|
||||
toast: deps.toast,
|
||||
navigate: deps.navigate,
|
||||
onShowTaskDialog: deps.onShowTaskDialog,
|
||||
});
|
||||
}
|
||||
|
||||
return handled;
|
||||
@@ -291,6 +296,7 @@ async function handleLegacyAction(
|
||||
deps: {
|
||||
toast: (opts: { title?: string; description?: string; variant?: 'default' | 'destructive' }) => void;
|
||||
navigate?: (path: string) => void;
|
||||
onShowTaskDialog?: (tasks: Array<{ id: number; title: string }>) => void;
|
||||
},
|
||||
): Promise<void> {
|
||||
const nav = deps.navigate ?? navigate;
|
||||
@@ -317,9 +323,13 @@ async function handleLegacyAction(
|
||||
break;
|
||||
}
|
||||
case 'show_list': {
|
||||
// Legacy show_list has no direct screen — notify the user instead.
|
||||
const titles = action.tasks.map((t) => t.title).join(', ');
|
||||
deps.toast({ title: 'Найдены задачи', description: titles || 'Список пуст' });
|
||||
if (deps.onShowTaskDialog && action.tasks.length > 0) {
|
||||
deps.onShowTaskDialog(action.tasks);
|
||||
} else {
|
||||
// Fallback when no dialog handler is provided.
|
||||
const titles = action.tasks.map((t) => t.title).join(', ');
|
||||
deps.toast({ title: 'Найдены задачи', description: titles || 'Список пуст' });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,13 @@ import { runOfflineAutomations, handleAutomationActions, type ClientAutomationRe
|
||||
import { checkServerReachable } from '@/lib/syncEngine';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Loader2, Terminal, ArrowLeft } from 'lucide-react';
|
||||
import { apiRequest } from '@/lib/queryClient';
|
||||
|
||||
@@ -17,6 +24,10 @@ export default function QrHandler() {
|
||||
|
||||
const [results, setResults] = useState<ClientAutomationResult[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [taskDialog, setTaskDialog] = useState<{ open: boolean; tasks: Array<{ id: number; title: string }> }>({
|
||||
open: false,
|
||||
tasks: [],
|
||||
});
|
||||
|
||||
const templateKey = params.templateKey ?? '';
|
||||
const objectId = params.objectId ? parseInt(params.objectId) : undefined;
|
||||
@@ -57,7 +68,11 @@ export default function QrHandler() {
|
||||
if (res.error) {
|
||||
toast({ title: 'Ошибка автоматизации', description: res.error, variant: 'destructive' });
|
||||
} else if (res.result) {
|
||||
await handleAutomationActions(res.result, { toast, navigate });
|
||||
await handleAutomationActions(res.result, {
|
||||
toast,
|
||||
navigate,
|
||||
onShowTaskDialog: (tasks) => setTaskDialog({ open: true, tasks }),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +97,11 @@ export default function QrHandler() {
|
||||
);
|
||||
for (const res of data.results) {
|
||||
if (res.result) {
|
||||
await handleAutomationActions(res.result, { toast, navigate });
|
||||
await handleAutomationActions(res.result, {
|
||||
toast,
|
||||
navigate,
|
||||
onShowTaskDialog: (tasks) => setTaskDialog({ open: true, tasks }),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -165,6 +184,30 @@ export default function QrHandler() {
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Dialog open={taskDialog.open} onOpenChange={(open) => setTaskDialog((prev) => ({ ...prev, open }))}>
|
||||
<DialogContent className="max-w-sm">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-base">Найдены заявки</DialogTitle>
|
||||
<DialogDescription>Выберите задачу для открытия</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-2 max-h-[60vh] overflow-auto">
|
||||
{taskDialog.tasks.map((task) => (
|
||||
<Button
|
||||
key={task.id}
|
||||
variant="outline"
|
||||
className="w-full justify-start h-auto py-2 px-3 text-left"
|
||||
onClick={() => {
|
||||
setTaskDialog({ open: false, tasks: [] });
|
||||
navigate(`/forms/11/tasks/${task.id}`);
|
||||
}}
|
||||
>
|
||||
<span className="text-sm">#{task.id} {task.title}</span>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user