PMFlow/frontend/src/components/sstc/SSTCTaskCreateDialog.tsx

110 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react";
import { useMutation } from "@tanstack/react-query";
import { Plus } from "lucide-react";
import { sstcApi } from "@/api/sstc";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
interface SelectedCharterLike {
id: string;
}
interface SSTCTaskCreateDialogProps {
projectId: string;
stageLocked: boolean;
selectedCharter: SelectedCharterLike | null;
onRefresh: () => Promise<void> | void;
}
export function SSTCTaskCreateDialog({
projectId,
stageLocked,
selectedCharter,
onRefresh,
}: SSTCTaskCreateDialogProps) {
const [newTaskOpen, setNewTaskOpen] = useState(false);
const [newTaskTitle, setNewTaskTitle] = useState("");
const [newTaskDesc, setNewTaskDesc] = useState("");
const [newTaskPriority, setNewTaskPriority] = useState("medium");
const [newTaskHours, setNewTaskHours] = useState("");
const [newTaskDueDate, setNewTaskDueDate] = useState("");
const createTaskMutation = useMutation({
mutationFn: () =>
sstcApi.createTask(projectId, selectedCharter!.id, {
title: newTaskTitle,
description: newTaskDesc || undefined,
priority: newTaskPriority,
estimated_hours: newTaskHours ? Number(newTaskHours) : undefined,
due_date: newTaskDueDate || undefined,
}),
onSuccess: () => {
setNewTaskOpen(false);
setNewTaskTitle("");
setNewTaskDesc("");
setNewTaskHours("");
setNewTaskDueDate("");
onRefresh();
},
});
return (
<>
<Button
size="sm"
variant="outline"
className="border-slate-200 bg-white text-slate-700 hover:bg-slate-50"
disabled={!selectedCharter || stageLocked}
onClick={() => setNewTaskOpen(true)}
>
<Plus className="mr-2 h-4 w-4" />
新建任务
</Button>
<Dialog open={newTaskOpen} onOpenChange={setNewTaskOpen}>
<DialogContent className="w-[min(560px,calc(100vw-1rem))] max-w-[calc(100vw-1rem)] sm:max-w-[560px]">
<DialogHeader>
<DialogTitle>新建任务</DialogTitle>
<DialogDescription>任务将绑定当前宪章(SSTC 强制)</DialogDescription>
</DialogHeader>
<div className="space-y-3">
<Input value={newTaskTitle} onChange={(e) => setNewTaskTitle(e.target.value)} placeholder="任务标题" />
<Textarea value={newTaskDesc} onChange={(e) => setNewTaskDesc(e.target.value)} placeholder="任务描述" />
<div className="grid grid-cols-1 gap-2 sm:grid-cols-3">
<select
className="rounded-md border bg-background px-2 py-2 text-sm"
value={newTaskPriority}
onChange={(e) => setNewTaskPriority(e.target.value)}
>
<option value="high">P0 / 高</option>
<option value="medium">P1 / 中</option>
<option value="low">P2 / 低</option>
</select>
<Input value={newTaskHours} onChange={(e) => setNewTaskHours(e.target.value)} placeholder="工时(小时)" />
<Input value={newTaskDueDate} onChange={(e) => setNewTaskDueDate(e.target.value)} placeholder="截止时间(标准格式)" />
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setNewTaskOpen(false)}>取消</Button>
<Button
onClick={() => createTaskMutation.mutate()}
disabled={!newTaskTitle.trim() || !selectedCharter || createTaskMutation.isPending}
>
创建
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}