From 239e547a5d623bea5755a295e1e6f5702ce9cc3c Mon Sep 17 00:00:00 2001 From: sky121113 Date: Tue, 20 Jan 2026 10:57:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=97=A5=E6=9C=9F=E6=99=82?= =?UTF-8?q?=E5=8D=80=E5=81=8F=E7=A7=BB=E5=B0=8E=E8=87=B4=E9=A1=AF=E7=A4=BA?= =?UTF-8?q?=E5=B0=91=E4=B8=80=E5=A4=A9=E7=9A=84=E5=95=8F=E9=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UtilityFee/UtilityFeeDialog.tsx | 41 +++++++++---------- resources/js/Pages/UtilityFee/Index.tsx | 4 +- resources/js/utils/format.ts | 37 +++++++++++++---- 3 files changed, 50 insertions(+), 32 deletions(-) diff --git a/resources/js/Components/UtilityFee/UtilityFeeDialog.tsx b/resources/js/Components/UtilityFee/UtilityFeeDialog.tsx index 90de36f..d888899 100644 --- a/resources/js/Components/UtilityFee/UtilityFeeDialog.tsx +++ b/resources/js/Components/UtilityFee/UtilityFeeDialog.tsx @@ -15,6 +15,7 @@ import { SearchableSelect } from "@/Components/ui/searchable-select"; import { useForm } from "@inertiajs/react"; import { toast } from "sonner"; import { Calendar } from "lucide-react"; +import { getCurrentDate } from "@/utils/format"; export interface UtilityFee { id: number; @@ -51,7 +52,7 @@ export default function UtilityFeeDialog({ availableCategories, }: UtilityFeeDialogProps) { const { data, setData, post, put, processing, errors, reset, clearErrors } = useForm({ - transaction_date: new Date().toISOString().split("T")[0], + transaction_date: getCurrentDate(), category: "", amount: "", invoice_number: "", @@ -74,7 +75,7 @@ export default function UtilityFeeDialog({ }); } else { reset(); - setData("transaction_date", new Date().toISOString().split("T")[0]); + setData("transaction_date", getCurrentDate()); } } }, [open, fee]); @@ -83,6 +84,12 @@ export default function UtilityFeeDialog({ e.preventDefault(); if (fee) { + // Validate invoice number format if present + if (data.invoice_number && !/^[A-Z]{2}-\d{8}$/.test(data.invoice_number)) { + toast.error("發票號碼格式錯誤,應為:AB-12345678"); + return; + } + put(route("utility-fees.update", fee.id), { onSuccess: () => { toast.success("紀錄已更新"); @@ -94,6 +101,12 @@ export default function UtilityFeeDialog({ } }); } else { + // Validate invoice number format if present + if (data.invoice_number && !/^[A-Z]{2}-\d{8}$/.test(data.invoice_number)) { + toast.error("發票號碼格式錯誤,應為:AB-12345678"); + return; + } + post(route("utility-fees.store"), { onSuccess: () => { toast.success("公共事業費已記錄"); @@ -124,13 +137,13 @@ export default function UtilityFeeDialog({ 費用日期 *
- + setData("transaction_date", e.target.value)} - className={`pl-9 ${errors.transaction_date ? "border-red-500" : ""}`} + className={`pl-9 block w-full ${errors.transaction_date ? "border-red-500" : ""}`} required />
@@ -176,26 +189,10 @@ export default function UtilityFeeDialog({ { - let value = e.target.value.toUpperCase(); - // Remove non-alphanumeric chars - const raw = value.replace(/[^A-Z0-9]/g, ''); - - // Auto-insert hyphen after 2 chars if we have length > 2 - if (raw.length > 2) { - value = `${raw.slice(0, 2)}-${raw.slice(2)}`; - } else { - value = raw; - } - - // Limit max length (2 letters + 8 digits + 1 hyphen = 11 chars) - if (value.length > 11) value = value.slice(0, 11); - - setData("invoice_number", value); - }} + onChange={(e) => setData("invoice_number", e.target.value)} placeholder="例:AB-12345678" /> -

格式:AB-12345678 (系統自動格式化)

+

格式範例:AB-12345678

{errors.invoice_number &&

{errors.invoice_number}

} diff --git a/resources/js/Pages/UtilityFee/Index.tsx b/resources/js/Pages/UtilityFee/Index.tsx index 5c874e8..3439f12 100644 --- a/resources/js/Pages/UtilityFee/Index.tsx +++ b/resources/js/Pages/UtilityFee/Index.tsx @@ -232,7 +232,7 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }: {/* Date Range Start */}
- + - + { */ export const formatDate = (date: string): string => { if (!date) return "-"; - return new Date(date).toLocaleDateString("zh-TW"); + const datePart = date.split("T")[0].split(" ")[0]; + const parts = datePart.split("-").map(Number); + if (parts.length < 3 || parts.some(isNaN)) return date; + + const [y, m, d] = parts; + const dt = new Date(y, m - 1, d, 12, 0, 0); + const year = dt.getFullYear(); + const month = String(dt.getMonth() + 1).padStart(2, '0'); + const day = String(dt.getDate()).padStart(2, '0'); + + return `${year}/${month}/${day}`; }; /** @@ -29,12 +39,19 @@ export const formatDate = (date: string): string => { */ export const formatDateWithDayOfWeek = (date: string): string => { if (!date) return "-"; - return new Date(date).toLocaleDateString("zh-TW", { - year: "numeric", - month: "2-digit", - day: "2-digit", - weekday: "short", - }); + const datePart = date.split("T")[0].split(" ")[0]; + const parts = datePart.split("-").map(Number); + if (parts.length < 3 || parts.some(isNaN)) return date; + + const [y, m, d] = parts; + const dt = new Date(y, m - 1, d, 12, 0, 0); + + const year = dt.getFullYear(); + const month = String(dt.getMonth() + 1).padStart(2, '0'); + const day = String(dt.getDate()).padStart(2, '0'); + const weekDay = dt.toLocaleDateString("zh-TW", { weekday: "short" }); + + return `${year}/${month}/${day} (${weekDay})`; }; /** @@ -54,7 +71,11 @@ export const formatInvoiceNumber = (invoice: string | null | undefined): string * 獲取當前日期(YYYY-MM-DD 格式) */ export const getCurrentDate = (): string => { - return new Date().toISOString().split("T")[0]; + const now = new Date(); + const year = now.getFullYear(); + const month = String(now.getMonth() + 1).padStart(2, "0"); + const day = String(now.getDate()).padStart(2, "0"); + return `${year}-${month}-${day}`; }; /**