CANCERYS\kw093 2 months ago
parent
commit
5957a22010
15 changed files with 165 additions and 40 deletions
  1. +2
    -1
      src/app/api/jo/actions.ts
  2. +1
    -0
      src/app/api/jo/index.ts
  3. +1
    -1
      src/components/DashboardPage/DashboardPage.tsx
  4. +3
    -3
      src/components/DoSearch/DoSearch.tsx
  5. +53
    -15
      src/components/FinishedGoodSearch/FinishedGoodSearch.tsx
  6. +1
    -0
      src/components/JoSearch/JoCreateFormModal.tsx
  7. +11
    -8
      src/components/JoSearch/JoSearch.tsx
  8. +1
    -1
      src/components/JoSearch/JoSearchWrapper.tsx
  9. +1
    -1
      src/components/Jodetail/completeJobOrderRecord.tsx
  10. +1
    -1
      src/components/PutAwayScan/PutAwayModal.tsx
  11. +74
    -2
      src/components/SearchBox/SearchBox.tsx
  12. +1
    -1
      src/i18n/zh/dashboard.json
  13. +2
    -1
      src/i18n/zh/jo.json
  14. +12
    -4
      src/i18n/zh/pickOrder.json
  15. +1
    -1
      src/i18n/zh/purchaseOrder.json

+ 2
- 1
src/app/api/jo/actions.ts View File

@@ -22,7 +22,8 @@ export interface SaveJoResponse {
export interface SearchJoResultRequest extends Pageable { export interface SearchJoResultRequest extends Pageable {
code: string; code: string;
itemName?: string; itemName?: string;

planStart?: string;
planStartTo?: string;
} }






+ 1
- 0
src/app/api/jo/index.ts View File

@@ -25,6 +25,7 @@ export interface JobOrder {
pickLines?: JoDetailPickLine[]; pickLines?: JoDetailPickLine[];
status: JoStatus; status: JoStatus;
planStart?: number[]; planStart?: number[];
planStartTo?: string;
planEnd?: number[]; planEnd?: number[];
type: string; type: string;
// TODO pack below into StockInLineInfo // TODO pack below into StockInLineInfo


+ 1
- 1
src/components/DashboardPage/DashboardPage.tsx View File

@@ -58,7 +58,7 @@ const DashboardPage: React.FC<Props> = ({
<Grid item xs={12}> <Grid item xs={12}>
<CollapsibleCard title={t("Progress chart")}> <CollapsibleCard title={t("Progress chart")}>
<CardContent> <CardContent>
<Grid container spacing={2}>
<Grid container spacing={3}>
<Grid item xs={12} md={4}> <Grid item xs={12} md={4}>
<DashboardProgressChart /> <DashboardProgressChart />
</Grid> </Grid>


+ 3
- 3
src/components/DoSearch/DoSearch.tsx View File

@@ -393,15 +393,15 @@ if(orderStartDate != ""){


const result = await Swal.fire( const result = await Swal.fire(
{ {
icon: "info",
icon: "question",
title: t("Batch Release"), title: t("Batch Release"),
html: t("Selected Shop(s): ") + extractedIdsCount.toString() + `</p>`+ html: t("Selected Shop(s): ") + extractedIdsCount.toString() + `</p>`+
t("Selected Item(s): ") + extractedItemsCount.toString() + `</p>`, t("Selected Item(s): ") + extractedItemsCount.toString() + `</p>`,
showCancelButton: true, showCancelButton: true,
confirmButtonText: t("Confirm"), confirmButtonText: t("Confirm"),
cancelButtonText: t("Cancel"), cancelButtonText: t("Cancel"),
confirmButtonColor: "#638a01",
cancelButtonColor: "#d33"
confirmButtonColor: "#8dba00",
cancelButtonColor: "#F04438"
}); });
if (result.isConfirmed) { if (result.isConfirmed) {
Swal.fire({ Swal.fire({


+ 53
- 15
src/components/FinishedGoodSearch/FinishedGoodSearch.tsx View File

@@ -69,7 +69,6 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
const fetchReleasedOrderCount = useCallback(async () => { const fetchReleasedOrderCount = useCallback(async () => {
try { try {
const releasedOrders = await fetchReleasedDoPickOrders(); const releasedOrders = await fetchReleasedDoPickOrders();
// Count only orders that have a valid doOrderId
const validCount = releasedOrders.filter(order => order.doOrderId).length; const validCount = releasedOrders.filter(order => order.doOrderId).length;
setReleasedOrderCount(validCount); setReleasedOrderCount(validCount);
} catch (error) { } catch (error) {
@@ -105,7 +104,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
if(response.success){ if(response.success){
Swal.fire({ Swal.fire({
position: "bottom-end", position: "bottom-end",
icon: "info",
icon: "success",
text: t("Printed Successfully."), text: t("Printed Successfully."),
showConfirmButton: false, showConfirmButton: false,
timer: 1500 timer: 1500
@@ -130,21 +129,30 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
console.log("Found released orders:", releasedOrders); console.log("Found released orders:", releasedOrders);


const confirmResult = await Swal.fire({ const confirmResult = await Swal.fire({
title: t("Confirm Print"),
text: t(`Do you want to print ${releasedOrders.length} draft(s)?`),
title: t("Batch Print"),
text: t("Confirm print: (") + releasedOrders.length.toString() + t("piece(s))"),
icon: "question", icon: "question",
showCancelButton: true, showCancelButton: true,
confirmButtonText: t("Yes, print"),
confirmButtonText: t("Confirm"),
cancelButtonText: t("Cancel"), cancelButtonText: t("Cancel"),
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33"
confirmButtonColor: "#8dba00",
cancelButtonColor: "#F04438"
}); });


// If user cancels, exit the function
if (!confirmResult.isConfirmed) { if (!confirmResult.isConfirmed) {
return; return;
} }


Swal.fire({
title: t("Printing..."),
text: t("Please wait..."),
allowOutsideClick: false,
allowEscapeKey: false,
didOpen: () => {
Swal.showLoading();
}
});

for (const order of releasedOrders) { for (const order of releasedOrders) {
const { doOrderId, pickOrderId } = order; const { doOrderId, pickOrderId } = order;


@@ -170,7 +178,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
Swal.fire({ Swal.fire({
position: "bottom-end", position: "bottom-end",
icon: "success", icon: "success",
text: t(`Printed ${releasedOrders.length} draft(s) successfully.`),
text: t("Printed Successfully."),
showConfirmButton: false, showConfirmButton: false,
timer: 1500 timer: 1500
}); });
@@ -183,6 +191,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
const handleDN = useCallback(async () =>{ const handleDN = useCallback(async () =>{
const askNumofCarton = await Swal.fire({ const askNumofCarton = await Swal.fire({
title: t("Enter the number of cartons: "), title: t("Enter the number of cartons: "),
icon: "info",
input: "number", input: "number",
inputPlaceholder: t("Number of cartons"), inputPlaceholder: t("Number of cartons"),
inputAttributes:{ inputAttributes:{
@@ -201,6 +210,8 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
showCancelButton: true, showCancelButton: true,
confirmButtonText: t("Confirm"), confirmButtonText: t("Confirm"),
cancelButtonText: t("Cancel"), cancelButtonText: t("Cancel"),
confirmButtonColor: "#8dba00",
cancelButtonColor: "#F04438",
showLoaderOnConfirm: true, showLoaderOnConfirm: true,
allowOutsideClick: () => !Swal.isLoading() allowOutsideClick: () => !Swal.isLoading()
}); });
@@ -233,7 +244,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
if(response.success){ if(response.success){
Swal.fire({ Swal.fire({
position: "bottom-end", position: "bottom-end",
icon: "info",
icon: "success",
text: t("Printed Successfully."), text: t("Printed Successfully."),
showConfirmButton: false, showConfirmButton: false,
timer: 1500 timer: 1500
@@ -250,6 +261,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
const handleDNandLabel = useCallback(async () =>{ const handleDNandLabel = useCallback(async () =>{
const askNumofCarton = await Swal.fire({ const askNumofCarton = await Swal.fire({
title: t("Enter the number of cartons: "), title: t("Enter the number of cartons: "),
icon: "info",
input: "number", input: "number",
inputPlaceholder: t("Number of cartons"), inputPlaceholder: t("Number of cartons"),
inputAttributes:{ inputAttributes:{
@@ -268,6 +280,8 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
showCancelButton: true, showCancelButton: true,
confirmButtonText: t("Confirm"), confirmButtonText: t("Confirm"),
cancelButtonText: t("Cancel"), cancelButtonText: t("Cancel"),
confirmButtonColor: "#8dba00",
cancelButtonColor: "#F04438",
showLoaderOnConfirm: true, showLoaderOnConfirm: true,
allowOutsideClick: () => !Swal.isLoading() allowOutsideClick: () => !Swal.isLoading()
}); });
@@ -310,7 +324,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
if(LabelsResponse.success && DNResponse.success){ if(LabelsResponse.success && DNResponse.success){
Swal.fire({ Swal.fire({
position: "bottom-end", position: "bottom-end",
icon: "info",
icon: "success",
text: t("Printed Successfully."), text: t("Printed Successfully."),
showConfirmButton: false, showConfirmButton: false,
timer: 1500 timer: 1500
@@ -332,6 +346,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
const handleLabel = useCallback(async () =>{ const handleLabel = useCallback(async () =>{
const askNumofCarton = await Swal.fire({ const askNumofCarton = await Swal.fire({
title: t("Enter the number of cartons: "), title: t("Enter the number of cartons: "),
icon: "info",
input: "number", input: "number",
inputPlaceholder: t("Number of cartons"), inputPlaceholder: t("Number of cartons"),
inputAttributes:{ inputAttributes:{
@@ -350,6 +365,8 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
showCancelButton: true, showCancelButton: true,
confirmButtonText: t("Confirm"), confirmButtonText: t("Confirm"),
cancelButtonText: t("Cancel"), cancelButtonText: t("Cancel"),
confirmButtonColor: "#8dba00",
cancelButtonColor: "#F04438",
showLoaderOnConfirm: true, showLoaderOnConfirm: true,
allowOutsideClick: () => !Swal.isLoading() allowOutsideClick: () => !Swal.isLoading()
}); });
@@ -380,7 +397,7 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
if(response.success){ if(response.success){
Swal.fire({ Swal.fire({
position: "bottom-end", position: "bottom-end",
icon: "info",
icon: "success",
text: t("Printed Successfully."), text: t("Printed Successfully."),
showConfirmButton: false, showConfirmButton: false,
timer: 1500 timer: 1500
@@ -454,19 +471,40 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
window.dispatchEvent(new CustomEvent('pickOrderAssigned')); window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
} else if (res.code === "USER_BUSY") { } else if (res.code === "USER_BUSY") {
console.warn("⚠️ User already has pick orders in progress:", res.message); console.warn("⚠️ User already has pick orders in progress:", res.message);
Swal.fire({
icon: "warning",
title: t("Warning"),
text: t("You already have a pick order in progess. Please complete it first before taking next pick order."),
confirmButtonText: t("Confirm"),
confirmButtonColor: "#8dba00"
});
// ✅ Show warning but still refresh to show existing orders // ✅ Show warning but still refresh to show existing orders
alert(`Warning: ${res.message}`);
//alert(`Warning: ${res.message}`);
window.dispatchEvent(new CustomEvent('pickOrderAssigned')); window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
} else if (res.code === "NO_ORDERS") { } else if (res.code === "NO_ORDERS") {
console.log("ℹ️ No available pick orders for store", storeId); console.log("ℹ️ No available pick orders for store", storeId);
alert(`Info: ${res.message}`);
Swal.fire({
icon: "info",
title: t("Info"),
text: t("No available pick order(s) for this floor."),
confirmButtonText: t("Confirm"),
confirmButtonColor: "#8dba00"
});
//alert(`Info: ${res.message}`);
} else { } else {
console.log("ℹ️ Assignment result:", res.message); console.log("ℹ️ Assignment result:", res.message);
alert(`Info: ${res.message}`); alert(`Info: ${res.message}`);
} }
} catch (error) { } catch (error) {
console.error("❌ Error assigning by store:", error); console.error("❌ Error assigning by store:", error);
alert("Error occurred during assignment");
Swal.fire({
icon: "error",
title: t("Error"),
text: t("Error occurred during assignment."),
confirmButtonText: t("Confirm"),
confirmButtonColor: "#8dba00"
});
//alert("Error occurred during assignment");
} finally { } finally {
setIsAssigning(false); setIsAssigning(false);
} }


+ 1
- 0
src/components/JoSearch/JoCreateFormModal.tsx View File

@@ -181,6 +181,7 @@ const JoCreateFormModal: React.FC<Props> = ({
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<DateTimePicker <DateTimePicker
label={t("Plan Start")} label={t("Plan Start")}
views={['year','month','day','hours', 'minutes', 'seconds']}
format={`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`} format={`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`}
onChange={(newValue: Dayjs | null) => { onChange={(newValue: Dayjs | null) => {
handleDateTimePickerChange(newValue, field.onChange) handleDateTimePickerChange(newValue, field.onChange)


+ 11
- 8
src/components/JoSearch/JoSearch.tsx View File

@@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
import { Criterion } from "../SearchBox"; import { Criterion } from "../SearchBox";
import SearchResults, { Column, defaultPagingController } from "../SearchResults/SearchResults"; import SearchResults, { Column, defaultPagingController } from "../SearchResults/SearchResults";
import { EditNote } from "@mui/icons-material"; import { EditNote } from "@mui/icons-material";
import { arrayToDateString, integerFormatter } from "@/app/utils/formatUtil";
import { arrayToDateString, arrayToDateTimeString, integerFormatter } from "@/app/utils/formatUtil";
import { orderBy, uniqBy, upperFirst } from "lodash"; import { orderBy, uniqBy, upperFirst } from "lodash";
import SearchBox from "../SearchBox/SearchBox"; import SearchBox from "../SearchBox/SearchBox";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
@@ -31,10 +31,7 @@ interface Props {
bomCombo: BomCombo[] bomCombo: BomCombo[]
} }


type SearchQuery = Partial<Omit<JobOrder, "id">> & {
planStartFrom?: string;
planStartTo?: string;
};
type SearchQuery = Partial<Omit<JobOrder, "id">>;


type SearchParamNames = keyof SearchQuery; type SearchParamNames = keyof SearchQuery;


@@ -49,6 +46,7 @@ const JoSearch: React.FC<Props> = ({ defaultInputs, bomCombo }) => {
const [totalCount, setTotalCount] = useState(0) const [totalCount, setTotalCount] = useState(0)
const [isCreateJoModalOpen, setIsCreateJoModalOpen] = useState(false) const [isCreateJoModalOpen, setIsCreateJoModalOpen] = useState(false)


// console.log(inputs)
const [inventoryData, setInventoryData] = useState<InventoryResult[]>([]); const [inventoryData, setInventoryData] = useState<InventoryResult[]>([]);


const [detailedJos, setDetailedJos] = useState<Map<number, JobOrder>>(new Map()); const [detailedJos, setDetailedJos] = useState<Map<number, JobOrder>>(new Map());
@@ -138,7 +136,8 @@ const JoSearch: React.FC<Props> = ({ defaultInputs, bomCombo }) => {


const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => [ const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => [
{ label: t("Code"), paramName: "code", type: "text" }, { label: t("Code"), paramName: "code", type: "text" },
{ label: t("Item Name"), paramName: "itemName", type: "text" },
{ label: t("Item Name"), paramName: "itemName", type: "text" },
{ label: t("Plan Start"), label2: t("Plan Start To"), paramName: "planStart", type: "datetimeRange" },
], [t]) ], [t])


const columns = useMemo<Column<JobOrder>[]>( const columns = useMemo<Column<JobOrder>[]>(
@@ -194,7 +193,7 @@ const JoSearch: React.FC<Props> = ({ defaultInputs, bomCombo }) => {
align: "left", align: "left",
headerAlign: "left", headerAlign: "left",
renderCell: (row) => { renderCell: (row) => {
return row.planStart ? arrayToDateString(row.planStart, "output") : '-'
return row.planStart ? arrayToDateTimeString(row.planStart) : '-'
} }
}, },
{ {
@@ -273,6 +272,8 @@ const JoSearch: React.FC<Props> = ({ defaultInputs, bomCombo }) => {
const params: SearchJoResultRequest = { const params: SearchJoResultRequest = {
code: query.code, code: query.code,
itemName: query.itemName, itemName: query.itemName,
planStart: query.planStart,
planStartTo: query.planStartTo,
pageNum: pagingController.pageNum - 1, pageNum: pagingController.pageNum - 1,
pageSize: pagingController.pageSize, pageSize: pagingController.pageSize,
} }
@@ -364,7 +365,9 @@ const JoSearch: React.FC<Props> = ({ defaultInputs, bomCombo }) => {
const onSearch = useCallback((query: Record<SearchParamNames, string>) => { const onSearch = useCallback((query: Record<SearchParamNames, string>) => {
setInputs(() => ({ setInputs(() => ({
code: query.code, code: query.code,
itemName: query.itemName
itemName: query.itemName,
planStart: query.planStart,
planStartTo: query.planStartTo
})) }))
refetchData(query, "search"); refetchData(query, "search");
}, []) }, [])


+ 1
- 1
src/components/JoSearch/JoSearchWrapper.tsx View File

@@ -11,7 +11,7 @@ interface SubComponents {
const JoSearchWrapper: React.FC & SubComponents = async () => { const JoSearchWrapper: React.FC & SubComponents = async () => {
const defaultInputs: SearchJoResultRequest = { const defaultInputs: SearchJoResultRequest = {
code: "", code: "",
name: "",
itemName: "",
} }


const [ const [


+ 1
- 1
src/components/Jodetail/completeJobOrderRecord.tsx View File

@@ -321,7 +321,7 @@ const CompleteJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
if(response.success){ if(response.success){
Swal.fire({ Swal.fire({
position: "bottom-end", position: "bottom-end",
icon: "info",
icon: "success",
text: t("Printed Successfully."), text: t("Printed Successfully."),
showConfirmButton: false, showConfirmButton: false,
timer: 1500 timer: 1500


+ 1
- 1
src/components/PutAwayScan/PutAwayModal.tsx View File

@@ -380,7 +380,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId
<Grid container> <Grid container>
<Typography variant="h4" sx={{ fontWeight: 'bold', color: 'black' }} noWrap> <Typography variant="h4" sx={{ fontWeight: 'bold', color: 'black' }} noWrap>
{warehouseId > 0 ? `${warehouse.find((w) => w.id == warehouseId)?.name}` {warehouseId > 0 ? `${warehouse.find((w) => w.id == warehouseId)?.name}`
: `${warehouse.find((w) => w.id == 1)?.name} (預設)`}
: `${warehouse.find((w) => w.id == 1)?.name} (建議)`}
</Typography> </Typography>
</Grid> </Grid>




+ 74
- 2
src/components/SearchBox/SearchBox.tsx View File

@@ -15,7 +15,7 @@ import CardActions from "@mui/material/CardActions";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import RestartAlt from "@mui/icons-material/RestartAlt"; import RestartAlt from "@mui/icons-material/RestartAlt";
import Search from "@mui/icons-material/Search"; import Search from "@mui/icons-material/Search";
import dayjs from "dayjs";
import dayjs, { Dayjs } from "dayjs";
import "dayjs/locale/zh-hk"; import "dayjs/locale/zh-hk";
import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { DatePicker } from "@mui/x-date-pickers/DatePicker";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
@@ -29,6 +29,8 @@ import {
} from "@mui/material"; } from "@mui/material";
import MultiSelect from "@/components/SearchBox/MultiSelect"; import MultiSelect from "@/components/SearchBox/MultiSelect";
import { intersectionWith } from "lodash"; import { intersectionWith } from "lodash";
import { INPUT_DATE_FORMAT, INPUT_TIME_FORMAT, OUTPUT_DATE_FORMAT, OUTPUT_TIME_FORMAT, dayjsToDateTimeString } from "@/app/utils/formatUtil";
import { DateTimePicker } from "@mui/x-date-pickers";


interface BaseCriterion<T extends string> { interface BaseCriterion<T extends string> {
label: string; label: string;
@@ -86,6 +88,10 @@ interface DateRangeCriterion<T extends string> extends BaseCriterion<T> {
type: "dateRange"; type: "dateRange";
} }


interface DatetimeRangeCriterion<T extends string> extends BaseCriterion<T> {
type: "datetimeRange";
}

interface DateCriterion<T extends string> extends BaseCriterion<T> { interface DateCriterion<T extends string> extends BaseCriterion<T> {
type: "date"; type: "date";
} }
@@ -95,6 +101,7 @@ export type Criterion<T extends string> =
| SelectCriterion<T> | SelectCriterion<T>
| SelectWithLabelCriterion<T> | SelectWithLabelCriterion<T>
| DateRangeCriterion<T> | DateRangeCriterion<T>
| DatetimeRangeCriterion<T>
| DateCriterion<T> | DateCriterion<T>
| MultiSelectCriterion<T> | MultiSelectCriterion<T>
| AutocompleteCriterion<T>; | AutocompleteCriterion<T>;
@@ -135,7 +142,7 @@ function SearchBox<T extends string>({
: "", : "",
}; };


if (c.type === "dateRange") {
if (c.type === "dateRange" || c.type === "datetimeRange") {
tempCriteria = { tempCriteria = {
...tempCriteria, ...tempCriteria,
[c.paramName]: c.defaultValue ?? "", [c.paramName]: c.defaultValue ?? "",
@@ -216,6 +223,24 @@ function SearchBox<T extends string>({
}; };
}, []); }, []);


const makeDatetimeChangeHandler = useCallback((paramName: T) => {
return (value: Dayjs | null) => {
setInputs((i) => ({
...i,
[paramName]: value ? dayjsToDateTimeString(value) : null
}));
};
}, []);

const makeDatetimeToChangeHandler = useCallback((paramName: T) => {
return (value: Dayjs | null) => {
setInputs((i) => ({
...i,
[paramName + "To"]: value ? dayjsToDateTimeString(value) : null
}));
};
}, []);

const handleReset = () => { const handleReset = () => {
setInputs(defaultInputs); setInputs(defaultInputs);
onReset?.(); onReset?.();
@@ -397,6 +422,7 @@ function SearchBox<T extends string>({
<Box display="flex"> <Box display="flex">
<FormControl fullWidth> <FormControl fullWidth>
<DatePicker <DatePicker
format={`${OUTPUT_DATE_FORMAT}`}
label={t(c.label)} label={t(c.label)}
onChange={makeDateChangeHandler(c.paramName)} onChange={makeDateChangeHandler(c.paramName)}
value={ value={
@@ -416,6 +442,7 @@ function SearchBox<T extends string>({
</Box> </Box>
<FormControl fullWidth> <FormControl fullWidth>
<DatePicker <DatePicker
format={`${OUTPUT_DATE_FORMAT}`}
label={c.label2 ? t(c.label2) : null} label={c.label2 ? t(c.label2) : null}
onChange={makeDateToChangeHandler(c.paramName)} onChange={makeDateToChangeHandler(c.paramName)}
value={ value={
@@ -428,6 +455,50 @@ function SearchBox<T extends string>({
</Box> </Box>
</LocalizationProvider> </LocalizationProvider>
)} )}
{c.type === "datetimeRange" && (
<LocalizationProvider
dateAdapter={AdapterDayjs}
// TODO: Should maybe use a custom adapterLocale here to support YYYY-MM-DD
adapterLocale="zh-hk"
>
<Box display="flex">
<FormControl fullWidth>
<DateTimePicker
views={['year','month','day','hours', 'minutes', 'seconds']}
format={`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`}
label={t(c.label)}
onChange={makeDatetimeChangeHandler(c.paramName)}
value={
dayjs(inputs[c.paramName]).isValid()
? dayjs(inputs[c.paramName])
: null
}
/>
</FormControl>
<Box
display="flex"
alignItems="center"
justifyContent="center"
marginInline={2}
>
{"-"}
</Box>
<FormControl fullWidth>
<DateTimePicker
views={['year','month','day','hours', 'minutes', 'seconds']}
format={`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`}
label={c.label2 ? t(c.label2) : null}
onChange={makeDatetimeToChangeHandler(c.paramName)}
value={
dayjs(inputs[`${c.paramName}To`]).isValid()
? dayjs(inputs[`${c.paramName}To`])
: null
}
/>
</FormControl>
</Box>
</LocalizationProvider>
)}
{c.type === "date" && ( {c.type === "date" && (
<LocalizationProvider <LocalizationProvider
dateAdapter={AdapterDayjs} dateAdapter={AdapterDayjs}
@@ -437,6 +508,7 @@ function SearchBox<T extends string>({
<Box display="flex"> <Box display="flex">
<FormControl fullWidth> <FormControl fullWidth>
<DatePicker <DatePicker
format={`${OUTPUT_DATE_FORMAT}`}
label={t(c.label)} label={t(c.label)}
onChange={makeDateChangeHandler(c.paramName)} onChange={makeDateChangeHandler(c.paramName)}
/> />


+ 1
- 1
src/i18n/zh/dashboard.json View File

@@ -56,5 +56,5 @@
"No": "無", "No": "無",
"Responsible Escalation List": "負責的上報列表", "Responsible Escalation List": "負責的上報列表",
"show completed logs": "顯示已完成上報", "show completed logs": "顯示已完成上報",
"Rows per page": "每頁行數"
"Rows per page": "每頁行數"
} }

+ 2
- 1
src/i18n/zh/jo.json View File

@@ -271,5 +271,6 @@
"Total (Verified + Bad + Missing) must equal Required quantity": "驗證數量 + 不良數量 + 缺失數量必須等於需求數量", "Total (Verified + Bad + Missing) must equal Required quantity": "驗證數量 + 不良數量 + 缺失數量必須等於需求數量",
"BOM Status": "材料預備狀況", "BOM Status": "材料預備狀況",
"Estimated Production Date": "預計生產日期", "Estimated Production Date": "預計生產日期",
"Plan Start": "預計生產日期"
"Plan Start": "預計生產日期",
"Plan Start To": "預計生產日期(至)"
} }

+ 12
- 4
src/i18n/zh/pickOrder.json View File

@@ -367,9 +367,17 @@
"Enter missing quantity (required if no bad items)": "請輸入缺少數量(如果沒有不良項目)", "Enter missing quantity (required if no bad items)": "請輸入缺少數量(如果沒有不良項目)",
"Submit All Scanned": "提交所有已掃描項目", "Submit All Scanned": "提交所有已掃描項目",
"Submitting...": "提交中...", "Submitting...": "提交中...",
"COMPLETED": "已完成"

"COMPLETED": "已完成",
"Confirm print: (": "確認列印全部草稿?(總數量:",
"piece(s))": "份)",
"Printing...": "列印中",
"Please wait...": "請稍後",
"No available pick order(s) for this floor.": "此樓層沒有可用的提料單",
"You already have a pick order in progess. Please complete it first before taking next pick order.": "請先完成目前的提料單,再提取下一張",
"Error occurred during assignment.": "提料單分配錯誤",
"Info": "消息",
"Warning": "警告",
"Error": "錯誤",
"Batch Print": "批量列印"


} }

+ 1
- 1
src/i18n/zh/purchaseOrder.json View File

@@ -97,7 +97,7 @@
"acceptedWeight": "接受重量", "acceptedWeight": "接受重量",
"productionDate": "生產日期", "productionDate": "生產日期",
"reportQty": "上報數量", "reportQty": "上報數量",
"Default Warehouse": "預設倉庫",
"Default Warehouse": "建議倉位",
"Select warehouse": "選擇倉庫", "Select warehouse": "選擇倉庫",
"Putaway Detail": "上架詳情", "Putaway Detail": "上架詳情",
"Delivery Detail": "來貨詳情", "Delivery Detail": "來貨詳情",


Loading…
Cancel
Save