feat(workspace): 增加工作活动日报引擎

This commit is contained in:
Script Generator
2026-06-26 17:17:35 +08:00
parent 64491789ae
commit 4278e4d565
21 changed files with 1090 additions and 24 deletions

View File

@@ -5,6 +5,7 @@ import { X, AlertTriangle, Link2, ChevronRight, Clock, User, Tag, Play, Trash2,
import { StatusBadge } from './StatusBadge';
import { CategoryChip } from './CategoryChip';
import { useDevTaskStore } from '@/stores/useDevTaskStore';
import { useWorkActivityStore } from '@/stores/useWorkActivityStore';
import { useTaskCategoryStore } from '@/stores/useTaskCategoryStore';
import { useRequirementStore } from '@/stores/useRequirementStore';
import { useMemberStore } from '@/stores/useMemberStore';
@@ -29,6 +30,7 @@ interface Props {
export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose, contextLabel }: Props) {
const { tasks, changeStatus, setBlocked, deleteTask, updateTask } = useDevTaskStore();
const addProgressNote = useWorkActivityStore((s) => s.addProgressNote);
const { categories } = useTaskCategoryStore();
const { requirements } = useRequirementStore();
const { members } = useMemberStore();
@@ -36,6 +38,10 @@ export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose, contextLabel
const [transferTo, setTransferTo] = useState('');
const [showDelayInput, setShowDelayInput] = useState(false);
const [delayReason, setDelayReason] = useState('');
const [progressNote, setProgressNote] = useState('');
const [progressBlocker, setProgressBlocker] = useState('');
const [progressHelperId, setProgressHelperId] = useState('');
const [progressDelayRisk, setProgressDelayRisk] = useState('');
const task = tasks.find((t) => t.id === taskId);
if (!task) return null;
@@ -86,6 +92,28 @@ export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose, contextLabel
setBlockReason('');
};
const handleProgressNote = () => {
const note = progressNote.trim();
const blocker = progressBlocker.trim();
const delayRisk = progressDelayRisk.trim();
if (!note && !blocker && !delayRisk) return;
addProgressNote({
actorId: task.assigneeId,
sourceType: 'dev_task',
sourceId: task.id,
title: task.title,
note: note || '今日进展已更新',
blocker: blocker || undefined,
helperId: progressHelperId || undefined,
delayRisk: delayRisk || undefined,
});
setProgressNote('');
setProgressBlocker('');
setProgressHelperId('');
setProgressDelayRisk('');
};
return (
<div className="fixed inset-0 z-50 flex justify-end" onClick={onClose}>
<div className="w-full max-w-md h-full bg-[var(--bg)] border-l border-[var(--line)] shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
@@ -199,6 +227,50 @@ export function DevTaskDetailDrawer({ taskId, allTaskIds, onClose, contextLabel
</div>
</div>
{task.status !== 'todo' && task.status !== 'submitted' && (
<div className="rounded-xl border border-[var(--line)] bg-[var(--bg-card)] p-4 space-y-3">
<div className="text-[10px] text-[var(--ink-muted)] uppercase tracking-wide"></div>
<textarea
value={progressNote}
onChange={(e) => setProgressNote(e.target.value)}
placeholder="今日完成内容、剩余内容"
rows={3}
className="w-full resize-none rounded-lg border border-[var(--line)] bg-[var(--bg)] px-3 py-2 text-[12px] leading-5 text-[var(--ink)] focus:border-[var(--accent)] focus:outline-none"
/>
<div className="grid grid-cols-2 gap-2">
<input
value={progressBlocker}
onChange={(e) => setProgressBlocker(e.target.value)}
placeholder="阻塞原因"
className="h-8 rounded-lg border border-[var(--line)] bg-[var(--bg)] px-2 text-[12px] focus:border-orange-400 focus:outline-none"
/>
<select
value={progressHelperId}
onChange={(e) => setProgressHelperId(e.target.value)}
className="h-8 rounded-lg border border-[var(--line)] bg-[var(--bg)] px-2 text-[12px] text-[var(--ink)] focus:border-[var(--accent)] focus:outline-none"
>
<option value=""></option>
{members.filter((m) => m.name !== task.assigneeId).map((m) => <option key={m.id} value={m.name}>{m.name}</option>)}
</select>
</div>
<input
value={progressDelayRisk}
onChange={(e) => setProgressDelayRisk(e.target.value)}
placeholder="延期风险"
className="h-8 w-full rounded-lg border border-[var(--line)] bg-[var(--bg)] px-2 text-[12px] focus:border-orange-400 focus:outline-none"
/>
<div className="flex justify-end">
<button
onClick={handleProgressNote}
disabled={!progressNote.trim() && !progressBlocker.trim() && !progressDelayRisk.trim()}
className="h-8 px-3 rounded-lg text-[12px] font-medium bg-[var(--accent)] text-white hover:bg-[var(--accent-hover)] disabled:opacity-50"
>
</button>
</div>
</div>
)}
<div className="rounded-xl border border-[var(--line)] bg-[var(--bg-card)] p-4">
<div className="text-[10px] text-[var(--ink-muted)] uppercase tracking-wide mb-3 flex items-center gap-1.5"><CalendarRange className="h-3 w-3" /></div>
<div className="grid grid-cols-2 gap-y-2.5 gap-x-4 text-[12px]">