文件
hyb-oa/client/src/pages/reimbursement-detail/ReimbursementActions.tsx
T

132 行
4.2 KiB
TypeScript

import { useState } from "react";
import type { ReimbursementStatus } from "../../api/reimbursements";
import { Button } from "../../components/ui/button";
import { Card } from "../../components/ui/card";
import { Input } from "../../components/ui/input";
import { Textarea } from "../../components/ui/textarea";
type PaymentChannel = "bank" | "alipay" | "wechat" | "cash" | "other";
export type PayPayload = {
paymentVoucherNo: string;
paymentDate: string;
paymentChannel: PaymentChannel;
};
export interface ReimbursementActionsProps {
status: ReimbursementStatus;
canPay: boolean;
actionError: string;
isPending: boolean;
onSubmit: () => void;
onWithdraw: (comment: string) => void;
onPay: (payload: PayPayload) => void;
}
export function ReimbursementActions({
status,
canPay,
actionError,
isPending,
onSubmit,
onWithdraw,
onPay,
}: ReimbursementActionsProps) {
const [withdrawComment, setWithdrawComment] = useState("申请撤回并补充说明后重提");
const [paymentVoucherNo, setPaymentVoucherNo] = useState("");
const [paymentDate, setPaymentDate] = useState("2026-02-08");
const [paymentChannel, setPaymentChannel] = useState<PaymentChannel>("bank");
return (
<Card className="space-y-4 p-6">
<h3 className="text-base font-semibold text-zinc-900">可执行动作</h3>
{actionError ? (
<p
className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-600"
data-testid="reimbursement-action-error"
>
{actionError}
</p>
) : null}
<div className="flex flex-wrap gap-2">
<Button
data-testid="reimbursement-submit"
disabled={isPending || status !== "draft"}
onClick={onSubmit}
type="button"
>
提交报销
</Button>
</div>
<div className="space-y-2 rounded-lg border border-zinc-200 p-4">
<p className="text-sm font-medium text-zinc-800">撤回报销</p>
<Textarea
data-testid="reimbursement-withdraw-comment"
onChange={(event) => setWithdrawComment(event.target.value)}
rows={2}
value={withdrawComment}
/>
<Button
data-testid="reimbursement-withdraw"
variant="secondary"
disabled={isPending || status !== "reviewing" || withdrawComment.trim().length < 1}
onClick={() => onWithdraw(withdrawComment.trim())}
type="button"
>
撤回
</Button>
</div>
{canPay ? (
<div className="space-y-2 rounded-lg border border-zinc-200 p-4">
<p className="text-sm font-medium text-zinc-800">财务支付</p>
<Input
data-testid="reimbursement-pay-voucher-no"
onChange={(event) => setPaymentVoucherNo(event.target.value)}
placeholder="付款凭证号"
value={paymentVoucherNo}
/>
<Input
data-testid="reimbursement-pay-date"
onChange={(event) => setPaymentDate(event.target.value)}
type="date"
value={paymentDate}
/>
<select
className="h-11 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm"
data-testid="reimbursement-pay-channel"
onChange={(event) =>
setPaymentChannel(event.target.value as PaymentChannel)
}
value={paymentChannel}
>
<option value="bank">bank</option>
<option value="alipay">alipay</option>
<option value="wechat">wechat</option>
<option value="cash">cash</option>
<option value="other">other</option>
</select>
<Button
data-testid="reimbursement-pay"
variant="secondary"
disabled={isPending || !["approved", "paid"].includes(status)}
onClick={() =>
onPay({
paymentVoucherNo: paymentVoucherNo.trim(),
paymentDate,
paymentChannel,
})
}
type="button"
>
执行支付
</Button>
</div>
) : null}
</Card>
);
}