feat(版本详情): 接入计划时间与日期选择
This commit is contained in:
@@ -9,14 +9,22 @@ import { useRequirementStore } from '@/stores/useRequirementStore';
|
||||
import { useMemberStore } from '@/stores/useMemberStore';
|
||||
import { useAuthStore } from '@/stores/useAuthStore';
|
||||
import { resolveMemberDisplayName } from '@/lib/member-system';
|
||||
import { WorkDateTimePicker } from '@/components/WorkDateTimePicker';
|
||||
import type { Priority } from '@/lib/derive';
|
||||
import type { BugSeverity } from '@/lib/bug';
|
||||
import { isoToLocal, localToISO } from '@/lib/work-hours';
|
||||
|
||||
interface Props {
|
||||
testCaseId: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
function defaultPlannedFixLocal(): string {
|
||||
const d = new Date();
|
||||
d.setHours(18, 0, 0, 0);
|
||||
return isoToLocal(d.toISOString());
|
||||
}
|
||||
|
||||
export function BugCreateModal({ testCaseId, onClose }: Props) {
|
||||
const { createBug } = useBugStore();
|
||||
const { testCases } = useTestCaseStore();
|
||||
@@ -42,10 +50,12 @@ export function BugCreateModal({ testCaseId, onClose }: Props) {
|
||||
const [severity, setSeverity] = useState<BugSeverity>('major');
|
||||
const [priority, setPriority] = useState<Priority>(tc?.priority || 'P1');
|
||||
const [assigneeId, setAssigneeId] = useState(defaultAssignee);
|
||||
const [plannedFixLocal, setPlannedFixLocal] = useState(defaultPlannedFixLocal);
|
||||
const [images, setImages] = useState<string[]>([]);
|
||||
const fileRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const canSubmit = title.trim() && description.trim() && assigneeId;
|
||||
const plannedFixAt = localToISO(plannedFixLocal);
|
||||
const canSubmit = title.trim() && description.trim() && assigneeId && Boolean(plannedFixAt);
|
||||
|
||||
const handleFiles = (files: FileList | null) => {
|
||||
if (!files) return;
|
||||
@@ -72,6 +82,7 @@ export function BugCreateModal({ testCaseId, onClose }: Props) {
|
||||
priority,
|
||||
reportedBy: operator,
|
||||
assigneeId,
|
||||
plannedFixAt,
|
||||
images: images.length > 0 ? images : undefined,
|
||||
}, operator);
|
||||
onClose();
|
||||
@@ -154,6 +165,15 @@ export function BugCreateModal({ testCaseId, onClose }: Props) {
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[12px] text-[var(--ink-soft)] mb-1">计划修复时间 *</label>
|
||||
<WorkDateTimePicker
|
||||
value={plannedFixLocal}
|
||||
onChange={setPlannedFixLocal}
|
||||
placeholder="选择计划修复时间"
|
||||
defaultHour={18}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 pt-4 border-t border-[var(--line)] mt-4">
|
||||
<button onClick={onClose} className="h-8 px-3 rounded-lg text-[12px] font-medium border border-[var(--line)] text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)]">取消</button>
|
||||
|
||||
@@ -166,6 +166,7 @@ export function BugDetailDrawer({ bugId, onClose, contextLabel }: Props) {
|
||||
<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">基本信息</div>
|
||||
<div className="grid grid-cols-2 gap-y-3 gap-x-4 text-[12px]">
|
||||
<div><span className="text-[var(--ink-muted)]">计划修复:</span><span className="text-[var(--ink)] font-medium">{bug.plannedFixAt ? formatDateTime(bug.plannedFixAt) : '待排期'}</span></div>
|
||||
<div><span className="text-[var(--ink-muted)]">提交人:</span><span className="text-[var(--ink)]">{reporterName}</span></div>
|
||||
<div><span className="text-[var(--ink-muted)]">修复人:</span><span className="text-[var(--ink)] font-medium">{assigneeName}</span></div>
|
||||
<div><span className="text-[var(--ink-muted)]">提交:</span><span className="text-[var(--ink)]">{formatDateTime(bug.createdAt)}</span></div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { memo } from 'react';
|
||||
import { BugStatusBadge } from './BugStatusBadge';
|
||||
import { BUG_SEVERITY_LABEL, BUG_SEVERITY_COLOR, getBugActualHours } from '@/lib/bug';
|
||||
import { formatWorkHours } from '@/lib/work-hours';
|
||||
import { formatDateTimeShort } from '@/lib/format';
|
||||
import { resolveMemberDisplayName } from '@/lib/member-system';
|
||||
import { useMemberStore } from '@/stores/useMemberStore';
|
||||
import type { Bug } from '@/lib/bug';
|
||||
@@ -32,6 +33,9 @@ function BugRowImpl({ bug, testCaseNo, onClick }: Props) {
|
||||
<span className="text-[13px] text-[var(--ink)] flex-1 truncate">{bug.title}</span>
|
||||
<span className={`text-[10px] px-1.5 py-0.5 rounded shrink-0 ${BUG_SEVERITY_COLOR[bug.severity]}`}>{BUG_SEVERITY_LABEL[bug.severity]}</span>
|
||||
<BugStatusBadge status={bug.status} />
|
||||
<span className="text-[11px] text-[var(--ink-muted)] tabular-nums w-24 text-right shrink-0 whitespace-nowrap" title="计划修复时间">
|
||||
{bug.plannedFixAt ? formatDateTimeShort(bug.plannedFixAt) : '待排期'}
|
||||
</span>
|
||||
{actualHours > 0 && (
|
||||
<span className="text-[11px] text-[var(--ink-muted)] tabular-nums w-28 text-right shrink-0 whitespace-nowrap">{formatWorkHours(actualHours)}</span>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user