修正日期時區偏移導致顯示少一天的問題
All checks were successful
Koori-ERP-Deploy-System / deploy-demo (push) Successful in 57s
Koori-ERP-Deploy-System / deploy-production (push) Has been skipped

This commit is contained in:
2026-01-20 10:57:39 +08:00
parent c1d302f03e
commit 239e547a5d
3 changed files with 50 additions and 32 deletions

View File

@@ -15,6 +15,7 @@ import { SearchableSelect } from "@/Components/ui/searchable-select";
import { useForm } from "@inertiajs/react"; import { useForm } from "@inertiajs/react";
import { toast } from "sonner"; import { toast } from "sonner";
import { Calendar } from "lucide-react"; import { Calendar } from "lucide-react";
import { getCurrentDate } from "@/utils/format";
export interface UtilityFee { export interface UtilityFee {
id: number; id: number;
@@ -51,7 +52,7 @@ export default function UtilityFeeDialog({
availableCategories, availableCategories,
}: UtilityFeeDialogProps) { }: UtilityFeeDialogProps) {
const { data, setData, post, put, processing, errors, reset, clearErrors } = useForm({ const { data, setData, post, put, processing, errors, reset, clearErrors } = useForm({
transaction_date: new Date().toISOString().split("T")[0], transaction_date: getCurrentDate(),
category: "", category: "",
amount: "", amount: "",
invoice_number: "", invoice_number: "",
@@ -74,7 +75,7 @@ export default function UtilityFeeDialog({
}); });
} else { } else {
reset(); reset();
setData("transaction_date", new Date().toISOString().split("T")[0]); setData("transaction_date", getCurrentDate());
} }
} }
}, [open, fee]); }, [open, fee]);
@@ -83,6 +84,12 @@ export default function UtilityFeeDialog({
e.preventDefault(); e.preventDefault();
if (fee) { 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), { put(route("utility-fees.update", fee.id), {
onSuccess: () => { onSuccess: () => {
toast.success("紀錄已更新"); toast.success("紀錄已更新");
@@ -94,6 +101,12 @@ export default function UtilityFeeDialog({
} }
}); });
} else { } 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"), { post(route("utility-fees.store"), {
onSuccess: () => { onSuccess: () => {
toast.success("公共事業費已記錄"); toast.success("公共事業費已記錄");
@@ -124,13 +137,13 @@ export default function UtilityFeeDialog({
<span className="text-red-500">*</span> <span className="text-red-500">*</span>
</Label> </Label>
<div className="relative"> <div className="relative">
<Calendar className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-400" /> <Calendar className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-400 pointer-events-none" />
<Input <Input
id="transaction_date" id="transaction_date"
type="date" type="date"
value={data.transaction_date} value={data.transaction_date}
onChange={(e) => setData("transaction_date", e.target.value)} onChange={(e) => 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 required
/> />
</div> </div>
@@ -176,26 +189,10 @@ export default function UtilityFeeDialog({
<Input <Input
id="invoice_number" id="invoice_number"
value={data.invoice_number} value={data.invoice_number}
onChange={(e) => { onChange={(e) => setData("invoice_number", e.target.value)}
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);
}}
placeholder="例AB-12345678" placeholder="例AB-12345678"
/> />
<p className="text-xs text-gray-500">AB-12345678 ()</p> <p className="text-xs text-gray-500">AB-12345678</p>
{errors.invoice_number && <p className="text-sm text-red-500">{errors.invoice_number}</p>} {errors.invoice_number && <p className="text-sm text-red-500">{errors.invoice_number}</p>}
</div> </div>

View File

@@ -232,7 +232,7 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }:
{/* Date Range Start */} {/* Date Range Start */}
<div className="relative"> <div className="relative">
<Calendar className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-400" /> <Calendar className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-400 pointer-events-none" />
<Input <Input
type="date" type="date"
value={dateStart} value={dateStart}
@@ -244,7 +244,7 @@ export default function UtilityFeeIndex({ fees, availableCategories, filters }:
{/* Date Range End */} {/* Date Range End */}
<div className="relative"> <div className="relative">
<Calendar className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-400" /> <Calendar className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-400 pointer-events-none" />
<Input <Input
type="date" type="date"
value={dateEnd} value={dateEnd}

View File

@@ -21,7 +21,17 @@ export const formatCurrency = (num: number): string => {
*/ */
export const formatDate = (date: string): string => { export const formatDate = (date: string): string => {
if (!date) return "-"; 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 => { export const formatDateWithDayOfWeek = (date: string): string => {
if (!date) return "-"; if (!date) return "-";
return new Date(date).toLocaleDateString("zh-TW", { const datePart = date.split("T")[0].split(" ")[0];
year: "numeric", const parts = datePart.split("-").map(Number);
month: "2-digit", if (parts.length < 3 || parts.some(isNaN)) return date;
day: "2-digit",
weekday: "short", 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 格式) * 獲取當前日期YYYY-MM-DD 格式)
*/ */
export const getCurrentDate = (): string => { 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}`;
}; };
/** /**