LP6 完善请假采购体验与审批说明
这个提交包含在:
@@ -1,4 +1,4 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
import { mapApiErrorMessage } from "../api/errorMessages";
|
||||
@@ -33,6 +33,11 @@ import { Label } from "../components/ui/label";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
||||
import { Textarea } from "../components/ui/textarea";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../components/ui/tabs";
|
||||
import {
|
||||
formatApprovalHistoryTime,
|
||||
resolveLeaveStatusHint,
|
||||
workflowActionLabel,
|
||||
} from "../lib/approvalDisplay";
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
const CALENDAR_PAGE_SIZE = 100;
|
||||
@@ -218,6 +223,7 @@ export function LeaveRequestPage() {
|
||||
const [reason, setReason] = useState("");
|
||||
const [attachmentFile, setAttachmentFile] = useState<File | null>(null);
|
||||
const [attachmentInputKey, setAttachmentInputKey] = useState(0);
|
||||
const attachmentInputRef = useRef<HTMLInputElement | null>(null);
|
||||
const [editingLeaveRequest, setEditingLeaveRequest] = useState<LeaveRequestItem | null>(null);
|
||||
const [formError, setFormError] = useState("");
|
||||
const [withdrawTarget, setWithdrawTarget] = useState<{ id: string; label: string } | null>(null);
|
||||
@@ -340,6 +346,9 @@ export function LeaveRequestPage() {
|
||||
setReason("");
|
||||
setAttachmentFile(null);
|
||||
setAttachmentInputKey((current) => current + 1);
|
||||
if (attachmentInputRef.current) {
|
||||
attachmentInputRef.current.value = "";
|
||||
}
|
||||
setFormError("");
|
||||
}
|
||||
|
||||
@@ -353,6 +362,9 @@ export function LeaveRequestPage() {
|
||||
setReason(item.reason ?? "");
|
||||
setAttachmentFile(null);
|
||||
setAttachmentInputKey((current) => current + 1);
|
||||
if (attachmentInputRef.current) {
|
||||
attachmentInputRef.current.value = "";
|
||||
}
|
||||
setFormError("");
|
||||
}
|
||||
|
||||
@@ -564,7 +576,22 @@ export function LeaveRequestPage() {
|
||||
</TableCell>
|
||||
<TableCell>{formatRangeLabel(item)}</TableCell>
|
||||
<TableCell>{item.requestedDays}</TableCell>
|
||||
<TableCell><StatusBadge status={item.status} /></TableCell>
|
||||
<TableCell>
|
||||
<div className="space-y-1">
|
||||
<StatusBadge status={item.status} />
|
||||
<div className="max-w-xs text-xs text-zinc-500" data-testid="leave-status-hint">
|
||||
{resolveLeaveStatusHint(item)}
|
||||
</div>
|
||||
{item.approvalHistory.length ? (
|
||||
<div className="max-w-xs text-xs text-zinc-400">
|
||||
最近审批:{workflowActionLabel(item.approvalHistory[0].action)}
|
||||
{item.approvalHistory[0].comment ? ` · ${item.approvalHistory[0].comment}` : ""}
|
||||
{" · "}
|
||||
{formatApprovalHistoryTime(item.approvalHistory[0].createdAt)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="text-xs text-zinc-500">
|
||||
{item.attachment?.originalName ?? "-"}
|
||||
</TableCell>
|
||||
@@ -856,9 +883,11 @@ export function LeaveRequestPage() {
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="leave-attachment">附件</Label>
|
||||
<Input
|
||||
<input
|
||||
key={attachmentInputKey}
|
||||
ref={attachmentInputRef}
|
||||
id="leave-attachment"
|
||||
className="hidden"
|
||||
type="file"
|
||||
accept={selectedLeaveType?.attachmentMimeTypes?.join(",") || undefined}
|
||||
onChange={(event) => {
|
||||
@@ -866,6 +895,20 @@ export function LeaveRequestPage() {
|
||||
setAttachmentFile(nextFile);
|
||||
}}
|
||||
/>
|
||||
<div className="flex items-center gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
disabled={!selectedLeaveType}
|
||||
onClick={() => attachmentInputRef.current?.click()}
|
||||
>
|
||||
选择附件
|
||||
</Button>
|
||||
<span className="min-w-0 flex-1 truncate text-sm text-zinc-500" data-testid="leave-attachment-name">
|
||||
{currentAttachmentLabel ?? "未选择文件"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-zinc-500">
|
||||
{selectedLeaveType?.requiresAttachment
|
||||
? `当前假种要求上传附件(允许:${selectedLeaveType.attachmentMimeTypes.join(", ") || "默认文档/图片"})`
|
||||
|
||||
在新工单中引用
屏蔽一个用户