Selaa lähdekoodia

Merge branch 'master' of https://git.2fi-solutions.com/derek/FPSMS-frontend

# Conflicts:
#	src/components/DetailScheduleDetail/DetailScheudleDetailView.tsx
master
CANCERYS\kw093 1 kuukausi sitten
vanhempi
commit
7e50834b35
21 muutettua tiedostoa jossa 357 lisäystä ja 240 poistoa
  1. +4
    -5
      src/app/(main)/scheduling/detail/page.tsx
  2. +14
    -10
      src/app/(main)/scheduling/rough/page.tsx
  3. +22
    -1
      src/app/api/scheduling/actions.ts
  4. +12
    -12
      src/app/api/scheduling/index.ts
  5. +185
    -113
      src/components/DetailSchedule/DetailScheduleSearchView.tsx
  6. +14
    -2
      src/components/DetailSchedule/DetailScheduleWrapper.tsx
  7. +9
    -6
      src/components/DetailScheduleDetail/DetailInfoCard.tsx
  8. +3
    -3
      src/components/DetailScheduleDetail/DetailScheudleDetailView.tsx
  9. +2
    -2
      src/components/ItemsSearch/ItemsSearch.tsx
  10. +9
    -8
      src/components/RoughSchedule/RoughSchedileSearchView.tsx
  11. +3
    -2
      src/components/RoughSchedule/RoughScheduleWrapper.tsx
  12. +3
    -3
      src/components/RoughScheduleDetail/DetailInfoCard.tsx
  13. +1
    -1
      src/components/RoughScheduleDetail/RoughScheduleDetailWrapper.tsx
  14. +5
    -6
      src/components/RoughScheduleDetail/RoughScheudleDetailView.tsx
  15. +16
    -18
      src/components/RoughScheduleDetail/ViewByBomDetails.tsx
  16. +7
    -7
      src/components/RoughScheduleDetail/ViewByFGDetails.tsx
  17. +2
    -2
      src/components/ScheduleTable/BomMaterialTable.tsx
  18. +11
    -11
      src/components/ScheduleTable/ScheduleTable.tsx
  19. +10
    -10
      src/components/SearchBox/SearchBox.tsx
  20. +22
    -16
      src/components/SearchResults/EditableSearchResults.tsx
  21. +3
    -2
      src/i18n/zh/schedule.json

+ 4
- 5
src/app/(main)/scheduling/detail/page.tsx Näytä tiedosto

@@ -2,7 +2,6 @@
// import DetailSchedule from "@/components/DetailSchedule";
// import { getServerI18n } from "@/i18n";

import { TypeEnum } from "../../../../app/utils/typeEnum";
import DetailSchedule from "../../../../components/DetailSchedule";
import { getServerI18n } from "../../../../i18n";
import { I18nProvider } from "@/i18n";
@@ -16,8 +15,8 @@ export const metadata: Metadata = {
};

const DetailScheduling: React.FC = async () => {
const project = TypeEnum.PRODUCT
const { t } = await getServerI18n("detailScheduling");
const { t } = await getServerI18n("schedule");
const type = "detailed"
// preloadClaims();

return (
@@ -32,9 +31,9 @@ const DetailScheduling: React.FC = async () => {
{t("Detail Scheduling")}
</Typography>
</Stack>
<I18nProvider namespaces={["detailScheduling", "items", "common","schedule"]}>
<I18nProvider namespaces={["schedule", "common"]}>
<Suspense fallback={<DetailSchedule.Loading />}>
<DetailSchedule />
<DetailSchedule type={type}/>
</Suspense>
</I18nProvider>
</>


+ 14
- 10
src/app/(main)/scheduling/rough/page.tsx Näytä tiedosto

@@ -1,6 +1,7 @@
// import { TypeEnum } from "@/app/utils/typeEnum";
// import RoughSchedule from "@/components/RoughSchedule";
// import { getServerI18n, I18nProvider } from "@/i18n";
import { testRoughSchedule } from "@/app/api/scheduling/actions";
import { TypeEnum } from "../../../../app/utils/typeEnum";
import RoughSchedule from "../../../../components/RoughSchedule";
import { getServerI18n, I18nProvider } from "../../../../i18n";
@@ -22,6 +23,10 @@ const roughScheduling: React.FC = async () => {
const type = "rough"
// preloadClaims();

// async function testingRoughSchedule() {
// await testRoughSchedule();
// }

return (
<>
<Stack
@@ -33,19 +38,18 @@ const roughScheduling: React.FC = async () => {
<Typography variant="h4" marginInlineEnd={2}>
{t("Demand Forecast")}
</Typography>
{/* <Button
variant="contained"
startIcon={<Add />}
LinkComponent={Link}
href="product/create"
>
{t("Create product")}
</Button> */}
variant="contained"
startIcon={<Add />}
onClick={() => testingRoughSchedule}
>
{t("Test Rough Scheduling")}
</Button> */}
</Stack>
<I18nProvider namespaces={["schedule", "common","items","project"]}>
<I18nProvider namespaces={["schedule", "common"]}>
<Suspense fallback={<RoughSchedule.Loading />}>
<RoughSchedule type={type}/>
<RoughSchedule type={type} />
</Suspense>
</I18nProvider>
</>


+ 22
- 1
src/app/api/scheduling/actions.ts Näytä tiedosto

@@ -4,13 +4,14 @@ import { convertObjToURLSearchParams } from "@/app/utils/commonUtil";
import { serverFetchJson } from "@/app/utils/fetchUtil"
import { BASE_API_URL } from "@/config/api"
import { cache } from "react"
import { ScheduleType } from ".";

export interface SearchProdSchedule {
scheduleAt?: string;
schedulePeriod?: string;
schedulePeriodTo?: string;
totalEstProdCount?: number;
type?: "manual" | "detailed" | "rough";
types?: ScheduleType[];
pageSize?: number;
pageNum?: number;
}
@@ -40,4 +41,24 @@ export const fetchProdSchedules = cache(async (data: SearchProdSchedule | null)
tags: ["prodSchedules"]
}
})
})

export const testRoughSchedule = cache(async () => {
return serverFetchJson(`${BASE_API_URL}/productionSchedule/testRoughSchedule`, {
method: "GET",
headers: { "Content-Type": "application/json" },
next: {
tags: ["prodSchedules"]
}
})
})

export const testDetailSchedule = cache(async () => {
return serverFetchJson(`${BASE_API_URL}/productionSchedule/testDetailSchedule`, {
method: "GET",
headers: { "Content-Type": "application/json" },
next: {
tags: ["prodSchedules"]
}
})
})

+ 12
- 12
src/app/api/scheduling/index.ts Näytä tiedosto

@@ -3,9 +3,9 @@ import { BASE_API_URL } from "@/config/api"
import { cache } from "react"
import "server-only"

export type ScheduleType = "rough" | "detail";
export type ScheduleType = "all" | "rough" | "detailed" | "manual";

export interface ProdScheduleResult {
export interface RoughProdScheduleResult {
id: number;
scheduleAt: number[];
schedulePeriod: number[];
@@ -13,13 +13,13 @@ export interface ProdScheduleResult {
totalEstProdCount: number;
totalFGType: number;
type: string;
prodScheduleLinesByFg: ProdScheduleLineResultByFg[];
prodScheduleLinesByFgByDate: { [assignDate: number]: ProdScheduleLineResultByFg[] };
prodScheduleLinesByBom: ProdScheduleLineResultByBom[];
prodScheduleLinesByBomByDate: { [assignDate: number]: ProdScheduleLineResultByBomByDate[] };
prodScheduleLinesByFg: RoughProdScheduleLineResultByFg[];
prodScheduleLinesByFgByDate: { [assignDate: number]: RoughProdScheduleLineResultByFg[] };
prodScheduleLinesByBom: RoughProdScheduleLineResultByBom[];
prodScheduleLinesByBomByDate: { [assignDate: number]: RoughProdScheduleLineResultByBomByDate[] };
}

export interface ProdScheduleLineResultByFg {
export interface RoughProdScheduleLineResultByFg {
id: number;
code: string;
name: string;
@@ -30,10 +30,10 @@ export interface ProdScheduleLineResultByFg {
estCloseBal: number;
priority: number;
assignDate: number;
bomMaterials: ProdScheduleLineBomMaterialResult[];
bomMaterials: RoughProdScheduleLineBomMaterialResult[];
}

export interface ProdScheduleLineBomMaterialResult {
export interface RoughProdScheduleLineBomMaterialResult {
id: number;
code: string;
name: string;
@@ -43,7 +43,7 @@ export interface ProdScheduleLineBomMaterialResult {
uomName: string;
}

export interface ProdScheduleLineResultByBom {
export interface RoughProdScheduleLineResultByBom {
id: number,
code: string,
name: string,
@@ -60,7 +60,7 @@ export interface ProdScheduleLineResultByBom {
uomName: string,
}

export interface ProdScheduleLineResultByBomByDate {
export interface RoughProdScheduleLineResultByBomByDate {
id: number,
code: string,
name: string,
@@ -72,7 +72,7 @@ export interface ProdScheduleLineResultByBomByDate {
}

export const fetchProdScheduleDetail = cache(async (id: number) => {
return serverFetchJson<ProdScheduleResult>(`${BASE_API_URL}/productionSchedule/detail/${id}`, {
return serverFetchJson<RoughProdScheduleResult>(`${BASE_API_URL}/productionSchedule/detail/${id}`, {
method: "GET",
headers: { "Content-Type": "application/json" },
next: {


+ 185
- 113
src/components/DetailSchedule/DetailScheduleSearchView.tsx Näytä tiedosto

@@ -1,67 +1,75 @@
"use client";

import React, {useCallback, useEffect, useMemo, useState} from "react";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import SearchBox, { Criterion } from "../SearchBox";
import { ItemsResult} from "@/app/api/settings/item";
import { ItemsResult } from "@/app/api/settings/item";
import SearchResults, { Column } from "../SearchResults";
import { EditNote } from "@mui/icons-material";
import { useRouter, useSearchParams } from "next/navigation";
import { GridDeleteIcon } from "@mui/x-data-grid";
import { TypeEnum } from "@/app/utils/typeEnum";
import axios from "axios";
import {BASE_API_URL, NEXT_PUBLIC_API_URL} from "@/config/api";
import { BASE_API_URL, NEXT_PUBLIC_API_URL } from "@/config/api";
import { useTranslation } from "react-i18next";
import axiosInstance from "@/app/(main)/axios/axiosInstance";
import Qs from 'qs';
import EditableSearchResults from "@/components/SearchResults/EditableSearchResults"; // Make sure to import Qs
import { ScheduleType } from "@/app/api/scheduling";
import { ProdScheduleResult, SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions";
import { defaultPagingController } from "../SearchResults/SearchResults";
import { arrayToDateString, decimalFormatter } from "@/app/utils/formatUtil";
import dayjs from "dayjs";
import { uniqBy } from "lodash";

// may need move to "index" or "actions"
type RecordStructure = {
id: number,
scheduledPeriod: string,
scheduledAt: string,
productCount: number,
};
// type RecordStructure = {
// id: number,
// scheduledPeriod: string,
// scheduledAt: string,
// productCount: number,
// };

type Props = {
records: RecordStructure[];
type: ScheduleType;
// records: RecordStructure[];
defaultInputs: SearchProdSchedule;
};

type SearchQuery = Partial<Omit<RecordStructure, "id">>;
type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "pageSize" | "pageNum">>;
type SearchParamNames = keyof SearchQuery;

const DSOverview: React.FC<Props> = ({ records }) => {
const [filteredItems, setFilteredItems] = useState<RecordStructure[]>(records ?? []);
const { t } = useTranslation("detailScheduling");
const DSOverview: React.FC<Props> = ({ type, defaultInputs }) => {
const [filteredSchedules, setFilteredSchedules] = useState<ProdScheduleResult[]>([]);
const { t } = useTranslation("schedule");
const router = useRouter();
const [filterObj, setFilterObj] = useState({});
const [tempSelectedValue, setTempSelectedValue] = useState({});
const [pagingController, setPagingController] = useState({
pageNum: 1,
pageSize: 10,
totalCount: 0,
})

const [mode, redirPath] = useMemo(() => {
// var typeId = TypeEnum.CONSUMABLE_ID
let title = "";
const mode = "Search";
let redirPath = "";
title = "Product";
redirPath = "/scheduling/detail";
return [mode, redirPath];
}, []);
// const [filterObj, setFilterObj] = useState({});
// const [tempSelectedValue, setTempSelectedValue] = useState({});
const [pagingController, setPagingController] = useState(defaultPagingController)
const [totalCount, setTotalCount] = useState(0)
const [inputs, setInputs] = useState(defaultInputs)
const typeOptions = [
{
value: "detailed",
label: t("Detailed")
},
{
value: "manual",
label: t("Manual")
},
]

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() =>
[
{ label: t("Schedule Period"), paramName: "scheduledPeriod", type: "dateRange" },
{ label: t("Scheduled At"), paramName: "scheduledAt", type: "dateRange" },
{ label: t("Product Count"), paramName: "productCount", type: "text" },
() => {
var searchCriteria: Criterion<SearchParamNames>[] = [
{ label: t("Schedule Period"), label2: t("Schedule Period To"), paramName: "schedulePeriod", type: "dateRange" },
{ label: t("Production Date"), paramName: "scheduleAt", type: "date" },
{ label: t("Product Count"), paramName: "totalEstProdCount", type: "text" },
{ label: t("Type"), paramName: "types", type: "autocomplete", options: typeOptions },
]
,
[t, records]
return searchCriteria
},
[t]
);

// const onDetailClick = useCallback(
@@ -71,36 +79,54 @@ const DSOverview: React.FC<Props> = ({ records }) => {
// [router]
// );

const onDeleteClick = useCallback(
(item: ItemsResult) => {},
[router]
);
// const onDeleteClick = useCallback(
// (item: ItemsResult) => {},
// [router]
// );

const onDetailClick = (record: any) => {
const onDetailClick = (record: ProdScheduleResult) => {
console.log("[debug] record", record);
router.push(`/scheduling/detail/edit?id=${record.id}`);

}

const columns = useMemo<Column<RecordStructure>[]>(
const columns = useMemo<Column<ProdScheduleResult>[]>(
() => [
{
name: "id",
label: t("Details"),
onClick: (record)=>onDetailClick(record),
onClick: (record) => onDetailClick(record),
buttonIcon: <EditNote />,
},
{
name: "scheduledPeriod",
name: "schedulePeriod",
label: t("Demand Forecast Period"),
renderCell: (params) => {
return `${arrayToDateString(params.schedulePeriod)} - ${arrayToDateString(params.schedulePeriodTo)}`
}
},
{
name: "scheduledAt",
label: t("Scheduled At"),
name: "scheduleAt",
label: t("Production Date"),
renderCell: (params) => {
return arrayToDateString(params.scheduleAt)
}
},
{
name: "productCount",
name: "totalEstProdCount",
label: t("Product Count(s)"),
headerAlign: "right",
align: "right",
renderCell: (params) => {
return decimalFormatter.format(params.totalEstProdCount)
}
},
{
name: "type",
label: t("Type"),
renderCell: (params) => {
return t(params.type)
}
},
// {
// name: "action",
@@ -109,92 +135,138 @@ const DSOverview: React.FC<Props> = ({ records }) => {
// onClick: onDeleteClick,
// },
],
[filteredItems]
[filteredSchedules]
);

const refetchData = useCallback(async (query: Record<SearchParamNames, string> | SearchProdSchedule, actionType: "reset" | "search" | "paging") => {
// console.log(query)
const defaultTypes = ["detailed", "manual"]
const convertedTypes = (query.types == undefined || typeof (query.types) == "string" ? query.types?.toLowerCase() == "all" ? defaultTypes : [query.types]
: query.types.some((ele) => ele.toLowerCase() === "all") ? defaultTypes : query.types) as ScheduleType[];

console.log(convertedTypes)
console.log(query.types)
const params: SearchProdSchedule = {
scheduleAt: dayjs(query?.scheduleAt).isValid() ? query?.scheduleAt : undefined,
schedulePeriod: dayjs(query?.schedulePeriod).isValid() ? query?.schedulePeriod : undefined,
schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid() ? query?.schedulePeriodTo : undefined,
totalEstProdCount: query?.totalEstProdCount ? Number(query?.totalEstProdCount) : undefined,
types: convertedTypes,
pageNum: pagingController.pageNum - 1,
pageSize: pagingController.pageSize
}
const response = await fetchProdSchedules(params)

// console.log(response)
if (response) {
setTotalCount(response.total)
switch (actionType) {
case "reset":
case "search":
setFilteredSchedules(() => response.records)
break;
case "paging":
setFilteredSchedules((fs) => uniqBy([...fs, ...response.records], "id"))
break;
}
}
}, [pagingController, setPagingController])

useEffect(() => {
refetchData(filterObj);
refetchData(inputs, "paging")
}, [pagingController])

}, [filterObj, pagingController.pageNum, pagingController.pageSize]);
// useEffect(() => {
// refetchData(filterObj);

const refetchData = async (filterObj: SearchQuery | null) => {
// }, [filterObj, pagingController.pageNum, pagingController.pageSize]);

const authHeader = axiosInstance.defaults.headers['Authorization'];
if (!authHeader) {
return; // Exit the function if the token is not set
}
// const refetchData = async (filterObj: SearchQuery | null) => {

const params ={
pageNum: pagingController.pageNum,
pageSize: pagingController.pageSize,
...filterObj,
...tempSelectedValue,
}
// const authHeader = axiosInstance.defaults.headers['Authorization'];
// if (!authHeader) {
// return; // Exit the function if the token is not set
// }

try {
const response = await axiosInstance.get<ItemsResult[]>(`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, {
params,
paramsSerializer: (params) => {
return Qs.stringify(params, { arrayFormat: 'repeat' });
},
});
//setFilteredItems(response.data.records);
setFilteredItems([
{
id: 1,
scheduledPeriod: "2025-05-11 to 2025-05-17",
scheduledAt: "2025-05-07",
productCount: 13,
},
{
id: 2,
scheduledPeriod: "2025-05-18 to 2025-05-24",
scheduledAt: "2025-05-14",
productCount: 15,
},
{
id: 3,
scheduledPeriod: "2025-05-25 to 2025-05-31",
scheduledAt: "2025-05-21",
productCount: 13,
},
])
setPagingController({
...pagingController,
totalCount: response.data.total
})
return response; // Return the data from the response
} catch (error) {
console.error('Error fetching items:', error);
throw error; // Rethrow the error for further handling
}
};
// const params = {
// pageNum: pagingController.pageNum,
// pageSize: pagingController.pageSize,
// ...filterObj,
// ...tempSelectedValue,
// }

// try {
// const response = await axiosInstance.get<ItemsResult[]>(`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, {
// params,
// paramsSerializer: (params) => {
// return Qs.stringify(params, { arrayFormat: 'repeat' });
// },
// });
// //setFilteredItems(response.data.records);
// setFilteredItems([
// {
// id: 1,
// scheduledPeriod: "2025-05-11 to 2025-05-17",
// scheduledAt: "2025-05-07",
// productCount: 13,
// },
// {
// id: 2,
// scheduledPeriod: "2025-05-18 to 2025-05-24",
// scheduledAt: "2025-05-14",
// productCount: 15,
// },
// {
// id: 3,
// scheduledPeriod: "2025-05-25 to 2025-05-31",
// scheduledAt: "2025-05-21",
// productCount: 13,
// },
// ])
// setPagingController({
// ...pagingController,
// totalCount: response.data.total
// })
// return response; // Return the data from the response
// } catch (error) {
// console.error('Error fetching items:', error);
// throw error; // Rethrow the error for further handling
// }
// };

const onReset = useCallback(() => {
//setFilteredItems(items ?? []);
setFilterObj({});
setTempSelectedValue({});
refetchData(null);
}, [records]);
// setFilterObj({});
// setTempSelectedValue({});
refetchData(inputs, "reset");
}, []);

return (
<>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
setFilterObj({
...query
})
setInputs(() => (
{
scheduleAt: query?.scheduleAt,
schedulePeriod: query?.schedulePeriod,
schedulePeriodTo: query?.schedulePeriodTo,
totalEstProdCount: Number(query?.totalEstProdCount),
types: query.types as unknown as ScheduleType[]
}
))
refetchData(query, "search")
}}
onReset={onReset}
/>
<SearchResults<RecordStructure>
items={filteredItems}
<SearchResults<ProdScheduleResult>
items={filteredSchedules}
columns={columns}
setPagingController={setPagingController}
pagingController={pagingController}
isAutoPaging={false}
// hasCollapse={false}
totalCount={totalCount}
// isAutoPaging={false}
// hasCollapse={false}
/>
</>
);


+ 14
- 2
src/components/DetailSchedule/DetailScheduleWrapper.tsx Näytä tiedosto

@@ -1,14 +1,26 @@
import React from "react";
import {DetailScheduleLoading} from "./DetailScheduleLoading";
import DSOverview from "./DetailScheduleSearchView";
import { ScheduleType } from "@/app/api/scheduling";
import { SearchProdSchedule } from "@/app/api/scheduling/actions";

interface SubComponents {
Loading: typeof DetailScheduleLoading;
}

const DetailScheduleWrapper: React.FC & SubComponents = async () => {
type Props = {
type: ScheduleType
}

const DetailScheduleWrapper: React.FC<Props> & SubComponents = async ({
type
}) => {

const defaultInputs: SearchProdSchedule = {
types: ["detailed", "manual"]
}

return <DSOverview records={[]} />;
return <DSOverview type={type} defaultInputs={defaultInputs} />;
};

DetailScheduleWrapper.Loading = DetailScheduleLoading;


+ 9
- 6
src/components/DetailScheduleDetail/DetailInfoCard.tsx Näytä tiedosto

@@ -23,11 +23,14 @@ import { SaveDetailSchedule } from "./DetailScheudleDetailView";
// temp interface input

type Props = {
recordDetails: SaveDetailSchedule;
// recordDetails: SaveDetailSchedule;
isEditing: boolean;
};

const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing }) => {
const DetailInfoCard: React.FC<Props> = ({
// recordDetails,
isEditing
}) => {
const {
t,
i18n: { language },
@@ -39,12 +42,12 @@ const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing }) => {
formState: { errors, defaultValues, touchedFields },
} = useFormContext<SaveDetailSchedule>();

const [details, setDetails] = useState<SaveDetailSchedule|null>(null);
const [details, setDetails] = useState<SaveDetailSchedule | undefined>(undefined);

useEffect(() => {
console.log("[debug] record details", recordDetails)
setDetails(recordDetails);
}, [recordDetails])
console.log("[debug] record details", defaultValues)
setDetails(defaultValues as SaveDetailSchedule);
}, [defaultValues])

useEffect(() => {
console.log("[debug] isEdit", isEditing)


+ 3
- 3
src/components/DetailScheduleDetail/DetailScheudleDetailView.tsx Näytä tiedosto

@@ -36,7 +36,7 @@ type Props = {
isEditMode: boolean;
// type: TypeEnum;
defaultValues: Partial<SaveDetailSchedule> | undefined;
qcChecks: ItemQc[]
// qcChecks: ItemQc[]
};

const DetailScheduleDetailView: React.FC<Props> = ({
@@ -89,7 +89,7 @@ const DetailScheduleDetailView: React.FC<Props> = ({
productionDate: "2025-05-07",
totalJobOrders: 13,
totalProductionQty: 21000,
},
} as SaveDetailSchedule,
});
const errors = formProps.formState.errors;

@@ -157,7 +157,7 @@ const DetailScheduleDetailView: React.FC<Props> = ({
{/* </Typography>*/}
{/*</Grid>*/}
<DetailInfoCard
recordDetails={formProps.formState.defaultValues as SaveDetailSchedule}
// recordDetails={formProps.formState.defaultValues}
isEditing={isEdit}
/>
<Stack


+ 2
- 2
src/components/ItemsSearch/ItemsSearch.tsx Näytä tiedosto

@@ -2,7 +2,7 @@

import { useCallback, useEffect, useMemo, useState } from "react";
import SearchBox, { Criterion } from "../SearchBox";
import { ItemsResult } from "@/app/api/settings/item";
import { ItemsResult, ItemsResultResponse } from "@/app/api/settings/item";
import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults";
import { EditNote } from "@mui/icons-material";
@@ -85,7 +85,7 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
...filterObj,
};
try {
const response = await axiosInstance.get<ItemsResult[]>(
const response = await axiosInstance.get<ItemsResultResponse>(
`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`,
{ params }
);


+ 9
- 8
src/components/RoughSchedule/RoughSchedileSearchView.tsx Näytä tiedosto

@@ -19,6 +19,7 @@ import { arrayToDateString, decimalFormatter } from "@/app/utils/formatUtil";
import { isEqual, uniqBy } from "lodash";
import dayjs from "dayjs";
import { defaultPagingController } from "../SearchResults/SearchResults";
import { ScheduleType } from "@/app/api/scheduling";

// type RecordStructure ={
// id: number,
@@ -27,12 +28,12 @@ import { defaultPagingController } from "../SearchResults/SearchResults";
// };

type Props = {
type: SearchProdSchedule["type"];
type: ScheduleType;
// initProdSchedules: ProdScheduleResultByPage;
defaultInputs: SearchProdSchedule;
};

type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "type" | "pageSize" | "pageNum">>;
type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "types" | "pageSize" | "pageNum">>;
type SearchParamNames = keyof SearchQuery;

const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => {
@@ -64,12 +65,12 @@ const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => {
// [router]
// );

const onDeleteClick = useCallback(
(item: ItemsResult) => { },
[router]
);
// const onDeleteClick = useCallback(
// (item: ItemsResult) => { },
// [router]
// );

const onDetailClick = (record: any) => {
const onDetailClick = (record: ProdScheduleResult) => {
console.log("[debug] record", record);
router.push(`/scheduling/rough/edit?id=${record.id}`);
}
@@ -127,7 +128,7 @@ const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => {
schedulePeriod: dayjs(query?.schedulePeriod).isValid() ? query?.schedulePeriod : undefined,
schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid() ? query?.schedulePeriodTo : undefined,
totalEstProdCount: query?.totalEstProdCount ? Number(query?.totalEstProdCount) : undefined,
type: "rough",
types: ["rough"],
pageNum: pagingController.pageNum - 1,
pageSize: pagingController.pageSize
}


+ 3
- 2
src/components/RoughSchedule/RoughScheduleWrapper.tsx Näytä tiedosto

@@ -2,13 +2,14 @@ import { fetchAllItems } from "@/app/api/settings/item";
import { RoughScheduleLoading } from "./RoughScheduleLoading";
import RSOverview from "./RoughSchedileSearchView";
import { SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions";
import { ScheduleType } from "@/app/api/scheduling";

interface SubComponents {
Loading: typeof RoughScheduleLoading;
}

type Props = {
type: SearchProdSchedule["type"]
type: ScheduleType
};

const RoughScheduleWrapper: React.FC<Props> & SubComponents = async (
@@ -18,7 +19,7 @@ const RoughScheduleWrapper: React.FC<Props> & SubComponents = async (
) => {
// console.log(type)
const defaultInputs: SearchProdSchedule = {
type: "rough"
types: ["rough"]
}

// const [


+ 3
- 3
src/components/RoughScheduleDetail/DetailInfoCard.tsx Näytä tiedosto

@@ -18,7 +18,7 @@ import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid";
import { TypeEnum } from "@/app/utils/typeEnum";
import { NumberInputProps } from "@/components/CreateItem/NumberInputProps";
import { arrayToDateString, integerFormatter } from "@/app/utils/formatUtil";
import { ProdScheduleResult } from "@/app/api/scheduling";
import { RoughProdScheduleResult } from "@/app/api/scheduling";
import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";

@@ -38,12 +38,12 @@ const DetailInfoCard: React.FC<Props> = ({ isEditing }) => {
getValues,
watch,
formState: { errors, defaultValues, touchedFields },
} = useFormContext<ProdScheduleResult>();
} = useFormContext<RoughProdScheduleResult>();

// const [details, setDetails] = useState(null);

useEffect(() => {
console.log("[debug] record details", getValues)
console.log("[debug] record details", getValues())
// setDetails(recordDetails);
}, [getValues])



+ 1
- 1
src/components/RoughScheduleDetail/RoughScheduleDetailWrapper.tsx Näytä tiedosto

@@ -15,7 +15,7 @@ type Props = {

const RoughScheduleDetailWrapper: React.FC<Props> & SubComponents = async ({ id, type }) => {
const prodSchedule = id ? await fetchProdScheduleDetail(id) : undefined
return (
<RoughScheduleDetailView
isEditMode={Boolean(id)}


+ 5
- 6
src/components/RoughScheduleDetail/RoughScheudleDetailView.tsx Näytä tiedosto

@@ -24,13 +24,13 @@ import ViewByFGDetails from "@/components/RoughScheduleDetail/ViewByFGDetails";
import ViewByBomDetails from "@/components/RoughScheduleDetail/ViewByBomDetails";
import ScheduleTable from "@/components/ScheduleTable";
import { Column } from "@/components/ScheduleTable/ScheduleTable";
import { ProdScheduleResult, ScheduleType } from "@/app/api/scheduling";
import { RoughProdScheduleResult, ScheduleType } from "@/app/api/scheduling";
import { arrayToDayjs, dayjsToDateString } from "@/app/utils/formatUtil";

type Props = {
isEditMode: boolean;
type: ScheduleType;
defaultValues: Partial<ProdScheduleResult> | undefined;
defaultValues: Partial<RoughProdScheduleResult> | undefined;
// qcChecks: ItemQc[]
};

@@ -42,7 +42,6 @@ const RoughScheduleDetailView: React.FC<Props> = ({
// console.log(type)
const apiRef = useGridApiRef();
const params = useSearchParams()
console.log(params.get("id"))
const [serverError, setServerError] = useState("");
const [tabIndex, setTabIndex] = useState(0);
const { t } = useTranslation("schedule")
@@ -51,7 +50,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({
//const title = "Demand Forecast Detail"

// console.log(typeId)
const formProps = useForm<ProdScheduleResult>({
const formProps = useForm<RoughProdScheduleResult>({
defaultValues: defaultValues ? defaultValues : {
},
});
@@ -88,7 +87,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({
router.replace(`/scheduling/rough`);
};

const onSubmit = useCallback<SubmitHandler<ProdScheduleResult>>(
const onSubmit = useCallback<SubmitHandler<RoughProdScheduleResult>>(
async (data, event) => {
let hasErrors = false;
console.log(errors)
@@ -109,7 +108,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({
);

// multiple tabs
const onSubmitError = useCallback<SubmitErrorHandler<ProdScheduleResult>>(
const onSubmitError = useCallback<SubmitErrorHandler<RoughProdScheduleResult>>(
(errors) => { },
[]
);


+ 16
- 18
src/components/RoughScheduleDetail/ViewByBomDetails.tsx Näytä tiedosto

@@ -21,7 +21,7 @@ import { RiceBowl } from "@mui/icons-material";
// import EditableSearchResults, { Column } from "@/components/SearchResults/EditableSearchResults";
import { decimalFormatter } from "@/app/utils/formatUtil";
import { GridRenderCellParams } from "@mui/x-data-grid";
import { ProdScheduleLineResultByBom, ProdScheduleLineResultByBomByDate, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling";
import { RoughProdScheduleLineResultByBom, RoughProdScheduleLineResultByBomByDate, RoughProdScheduleResult, ScheduleType } from "@/app/api/scheduling";
import ScheduleTable from "@/components/ScheduleTable";
import { Column } from "@/components/ScheduleTable/ScheduleTable";

@@ -63,7 +63,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
control,
getValues,
formState: { errors, defaultValues, touchedFields },
} = useFormContext<ProdScheduleResult>();
} = useFormContext<RoughProdScheduleResult>();
// const apiRef = useGridApiRef();

const { fields } = useFieldArray({
@@ -165,7 +165,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.availableQty) == "number") {
return decimalFormatter.format(row.availableQty)
}
@@ -180,7 +180,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.totalDemandQty) == "number") {
return decimalFormatter.format(row.totalDemandQty)
}
@@ -194,7 +194,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.demandQty1) == "number") {
return decimalFormatter.format(row.demandQty1)
}
@@ -208,7 +208,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.demandQty2) == "number") {
return decimalFormatter.format(row.demandQty2)
}
@@ -222,7 +222,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.demandQty3) == "number") {
return decimalFormatter.format(row.demandQty3)
}
@@ -236,7 +236,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.demandQty4) == "number") {
return decimalFormatter.format(row.demandQty4)
}
@@ -249,7 +249,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.demandQty5) == "number") {
return decimalFormatter.format(row.demandQty5)
}
@@ -263,7 +263,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.demandQty6) == "number") {
return decimalFormatter.format(row.demandQty6)
}
@@ -277,7 +277,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBom) => {
renderCell: (row: RoughProdScheduleLineResultByBom) => {
if (typeof (row.demandQty7) == "number") {
return decimalFormatter.format(row.demandQty7)
}
@@ -288,7 +288,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
[t]
);

const columns = useMemo<Column<ProdScheduleLineResultByBomByDate>[]>(
const columns = useMemo<Column<RoughProdScheduleLineResultByBomByDate>[]>(
() => [
{
field: "code",
@@ -317,7 +317,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBomByDate) => {
renderCell: (row: RoughProdScheduleLineResultByBomByDate) => {
if (typeof (row.availableQty) == "number") {
return decimalFormatter.format(row.availableQty)
}
@@ -331,7 +331,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
style: {
textAlign: "right",
},
renderCell: (row: ProdScheduleLineResultByBomByDate) => {
renderCell: (row: RoughProdScheduleLineResultByBomByDate) => {
if (typeof (row.demandQty) == "number") {
return decimalFormatter.format(row.demandQty)
}
@@ -342,15 +342,13 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
[]
);

console.log(getValues("prodScheduleLinesByBom"))

return (
<Grid container spacing={2}>
<Grid item xs={12} key={"all"}>
<Typography variant="overline" display="block" marginBlockEnd={1}>
{t("Material Demand List (7 Days)")}
</Typography>
<ScheduleTable<ProdScheduleLineResultByBom>
<ScheduleTable<RoughProdScheduleLineResultByBom>
// index={7}
type={type}
items={getValues("prodScheduleLinesByBom")}
@@ -368,7 +366,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod })
<Typography variant="overline" display="block" marginBlockEnd={1}>
{`${t("Material Demand Date")}: ${date}`}
</Typography>
<ScheduleTable<ProdScheduleLineResultByBomByDate>
<ScheduleTable<RoughProdScheduleLineResultByBomByDate>
// index={index}
type={type}
items={getValues("prodScheduleLinesByBomByDate")[index + 1]} // Use the corresponding records for the day


+ 7
- 7
src/components/RoughScheduleDetail/ViewByFGDetails.tsx Näytä tiedosto

@@ -21,7 +21,7 @@ import { RiceBowl } from "@mui/icons-material";
import ScheduleTable from "@/components/ScheduleTable";
import { Column } from "@/components/ScheduleTable/ScheduleTable";
import { arrayToDayjs, dayjsToDateString, decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";
import { ProdScheduleLineResultByFg, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling";
import { RoughProdScheduleLineResultByFg, RoughProdScheduleResult, ScheduleType } from "@/app/api/scheduling";

type Props = {
apiRef: MutableRefObject<GridApiCommunity>
@@ -50,7 +50,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) =
control,
getValues,
formState: { errors, defaultValues, touchedFields },
} = useFormContext<ProdScheduleResult>();
} = useFormContext<RoughProdScheduleResult>();

const { fields } = useFieldArray({
control,
@@ -125,7 +125,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) =
});
};

const columns = useMemo<Column<ProdScheduleLineResultByFg>[]>(
const columns = useMemo<Column<RoughProdScheduleLineResultByFg>[]>(
() => [
{
field: "code",
@@ -177,7 +177,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) =
[]
);

const overallColumns = useMemo<Column<ProdScheduleLineResultByFg>[]>(
const overallColumns = useMemo<Column<RoughProdScheduleLineResultByFg>[]>(
() => [
{
field: "code",
@@ -270,7 +270,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) =
<Typography variant="overline" display="block" marginBlockEnd={1}>
{t("FG Demand List (7 Days)")}
</Typography>
<ScheduleTable<ProdScheduleLineResultByFg>
<ScheduleTable<RoughProdScheduleLineResultByFg>
// index={7}
type={type}
items={getValues("prodScheduleLinesByFg")}
@@ -288,9 +288,9 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) =
<Typography variant="overline" display="block" marginBlockEnd={1}>
{`${t("FG Demand Date")}: ${date}`}
</Typography>
<ScheduleTable<ProdScheduleLineResultByFg>
<ScheduleTable<RoughProdScheduleLineResultByFg>
type={type}
items={getValues("prodScheduleLinesByFgByDate")[index + 1]} // Use the corresponding records for the day
items={getValues("prodScheduleLinesByFgByDate") && Object.entries(getValues("prodScheduleLinesByFgByDate")).length > 0 ? getValues("prodScheduleLinesByFgByDate")[index + 1] : []} // Use the corresponding records for the day
columns={columns}
setPagingController={updatePagingController}
pagingController={pagingController[index]}


+ 2
- 2
src/components/ScheduleTable/BomMaterialTable.tsx Näytä tiedosto

@@ -36,14 +36,14 @@ import { useSearchParams } from "next/navigation";
import { decimalFormatter } from "@/app/utils/formatUtil";
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
import HighlightOffIcon from '@mui/icons-material/HighlightOff';
import { ProdScheduleLineBomMaterialResult, ScheduleType } from "@/app/api/scheduling";
import { RoughProdScheduleLineBomMaterialResult, ScheduleType } from "@/app/api/scheduling";

interface ResultWithId {
id: number;
}

interface Props {
bomMaterial: ProdScheduleLineBomMaterialResult[];
bomMaterial: RoughProdScheduleLineBomMaterialResult[];
type: ScheduleType
}



+ 11
- 11
src/components/ScheduleTable/ScheduleTable.tsx Näytä tiedosto

@@ -23,7 +23,7 @@ import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";
import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline';
import { useTranslation } from "react-i18next";
import { ProdScheduleLineBomMaterialResult, ProdScheduleLineResultByFg, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling";
import { RoughProdScheduleLineBomMaterialResult, RoughProdScheduleLineResultByFg, RoughProdScheduleResult, ScheduleType } from "@/app/api/scheduling";

export interface ResultWithId {
id: string | number;
@@ -144,10 +144,10 @@ function ScheduleTable<T extends ResultWithId>({
return type === "rough";
}

function isDetailType(
function isDetailedType(
type: ScheduleType
): type is "detail" {
return type === "detail";
): type is "detailed" {
return type === "detailed";
}

function Row(props: { row: T }) {
@@ -157,7 +157,7 @@ function ScheduleTable<T extends ResultWithId>({
return (
<>
<TableRow hover tabIndex={-1} key={row.id}>
{isDetailType(type) && <TableCell>
{isDetailedType(type) && <TableCell>
<IconButton disabled={!isEdit}>
<PlayCircleOutlineIcon />
</IconButton>
@@ -167,12 +167,12 @@ function ScheduleTable<T extends ResultWithId>({
{(editingRowId === row.id) ? (
<>
{
isDetailType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}>
isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}>
<SaveIcon />
</IconButton>
}
{
isDetailType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}>
isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}>
<CancelIcon />
</IconButton>
}
@@ -190,13 +190,13 @@ function ScheduleTable<T extends ResultWithId>({
) : (
<>
{
isDetailType(type) && isEditable && <IconButton disabled={!isEdit}
isDetailedType(type) && isEditable && <IconButton disabled={!isEdit}
onClick={() => handleEditClick(row.id as number)}>
<EditIcon />
</IconButton>
}
{
isDetailType(type) && isEditable && <IconButton disabled={!isEdit}
isDetailedType(type) && isEditable && <IconButton disabled={!isEdit}
onClick={() => handleDeleteClick(row.id as number)}>
<DeleteIcon />
</IconButton>
@@ -278,7 +278,7 @@ function ScheduleTable<T extends ResultWithId>({
<TableCell>
<BomMaterialTable
type={type}
bomMaterial={(row as unknown as ProdScheduleLineResultByFg).bomMaterials}
bomMaterial={(row as unknown as RoughProdScheduleLineResultByFg).bomMaterials}
/>
</TableCell>
</TableRow>
@@ -298,7 +298,7 @@ function ScheduleTable<T extends ResultWithId>({
<Table stickyHeader>
<TableHead>
<TableRow>
{isDetailType(type) && <TableCell>{t("Release")}</TableCell>}
{isDetailedType(type) && <TableCell>{t("Release")}</TableCell>}
{(isEditable || hasCollapse) && <TableCell>{t("Actions")}</TableCell>} {/* Action Column Header */}
{columns.map((column, idx) => (
<TableCell style={column.style} key={`${column.field.toString()}${idx}`}>


+ 10
- 10
src/components/SearchBox/SearchBox.tsx Näytä tiedosto

@@ -196,7 +196,7 @@ function SearchBox<T extends string>({
<Grid key={c.paramName} item xs={6}>
{c.type === "text" && (
<TextField
label={c.label}
label={t(c.label)}
fullWidth
onChange={makeInputChangeHandler(c.paramName)}
value={inputs[c.paramName]}
@@ -204,7 +204,7 @@ function SearchBox<T extends string>({
)}
{c.type === "multi-select" && (
<MultiSelect
label={c.label}
label={t(c.label)}
options={c?.options}
selectedValues={c.filterObj?.[c.paramName] ?? []}
onChange={c.handleSelectionChange}
@@ -213,9 +213,9 @@ function SearchBox<T extends string>({
)}
{c.type === "select" && (
<FormControl fullWidth>
<InputLabel>{c.label}</InputLabel>
<InputLabel>{t(c.label)}</InputLabel>
<Select
label={c.label}
label={t(c.label)}
onChange={makeSelectChangeHandler(c.paramName)}
value={inputs[c.paramName]}
>
@@ -230,9 +230,9 @@ function SearchBox<T extends string>({
)}
{c.type === "select-labelled" && (
<FormControl fullWidth>
<InputLabel>{c.label}</InputLabel>
<InputLabel>{t(c.label)}</InputLabel>
<Select
label={c.label}
label={t(c.label)}
onChange={makeSelectChangeHandler(c.paramName)}
value={inputs[c.paramName]}
>
@@ -312,7 +312,7 @@ function SearchBox<T extends string>({
</MenuItem>
);
}}
renderInput={(params) => <TextField {...params} variant="outlined" label={c.label} />}
renderInput={(params) => <TextField {...params} variant="outlined" label={t(c.label)} />}
/>
)}
{c.type === "dateRange" && (
@@ -324,7 +324,7 @@ function SearchBox<T extends string>({
<Box display="flex">
<FormControl fullWidth>
<DatePicker
label={c.label}
label={t(c.label)}
onChange={makeDateChangeHandler(c.paramName)}
value={dayjs(inputs[c.paramName]).isValid() ? dayjs(inputs[c.paramName]) : null}
/>
@@ -339,7 +339,7 @@ function SearchBox<T extends string>({
</Box>
<FormControl fullWidth>
<DatePicker
label={c.label2}
label={c.label2 ? t(c.label2) : null}
onChange={makeDateToChangeHandler(c.paramName)}
value={dayjs(inputs[`${c.paramName}To`]).isValid() ? dayjs(inputs[`${c.paramName}To`]) : null}
/>
@@ -356,7 +356,7 @@ function SearchBox<T extends string>({
<Box display="flex">
<FormControl fullWidth>
<DatePicker
label={c.label}
label={t(c.label)}
onChange={makeDateChangeHandler(c.paramName)}
/>
</FormControl>


+ 22
- 16
src/components/SearchResults/EditableSearchResults.tsx Näytä tiedosto

@@ -1,6 +1,6 @@
"use client";

import React, { useEffect, useState } from "react";
import React, { CSSProperties, useEffect, useState } from "react";
import Paper from "@mui/material/Paper";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
@@ -23,6 +23,7 @@ import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";
import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline';
import { useTranslation } from "react-i18next";
import { RoughProdScheduleLineResultByFg } from "@/app/api/scheduling";
export interface ResultWithId {
id: string | number;
}
@@ -32,8 +33,9 @@ interface BaseColumn<T extends ResultWithId> {
label: string;
type: string;
options?: T[];
renderCell?: (T) => void;
style?: Partial<HTMLElement["style"]> & { [propName: string]: string };
renderCell?: (params: T) => React.ReactNode;
style?: Partial<HTMLElement["style"]> & { [propName: string]: string } & CSSProperties;
// style?: Partial<HTMLElement["style"]> & { [propName: string]: string };
}

interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> {
@@ -52,7 +54,11 @@ interface Props<T extends ResultWithId> {
noWrapper?: boolean,
setPagingController: (value: { pageNum: number; pageSize: number; totalCount: number, index?: number }) => void,
pagingController: { pageNum: number; pageSize: number; totalCount: number },
isAutoPaging: boolean
isAutoPaging: boolean,
index: any,
isEdit: any,
isEditable: any,
hasCollapse: any,
}

function EditableSearchResults<T extends ResultWithId>({
@@ -78,7 +84,7 @@ function EditableSearchResults<T extends ResultWithId>({
}, [items])
const handleChangePage = (_event: unknown, newPage: number) => {
setPage(newPage);
setPagingController({ ...pagingController, pageNum: newPage + 1 }, (index ?? -1));
// setPagingController({ ...pagingController, pageNum: newPage + 1 }, (index ?? -1));
};

const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
@@ -134,7 +140,7 @@ function EditableSearchResults<T extends ResultWithId>({
<>
<TableRow hover tabIndex={-1} key={row.id}>
<TableCell>
<IconButton disable={!isEdit}>
<IconButton disabled={!isEdit}>
<PlayCircleOutlineIcon />
</IconButton>
</TableCell>
@@ -208,15 +214,15 @@ function EditableSearchResults<T extends ResultWithId>({
onChange={(e) => handleInputChange(row.id as number, columnName, e.target.value)}
/>
);
case 'multi-select':
return (
<MultiSelect
//label={column.label}
options={column.options}
selectedValues={[]}
onChange={(selectedValues) => handleInputChange(row.id as number, columnName, selectedValues)}
/>
);
// case 'multi-select':
// return (
// <MultiSelect
// //label={column.label}
// options={column.options}
// selectedValues={[]}
// onChange={(selectedValues) => handleInputChange(row.id as number, columnName, selectedValues)}
// />
// );
case 'read-only':
return (
<span>
@@ -253,7 +259,7 @@ function EditableSearchResults<T extends ResultWithId>({
<TableRow>
<TableCell>
<TempInputGridForMockUp
stockInLine={row.lines as any[]}
stockInLine={(row as unknown as {lines: string[]}).lines as any[]}
/>
</TableCell>
</TableRow>


+ 3
- 2
src/i18n/zh/schedule.json Näytä tiedosto

@@ -10,7 +10,8 @@
"Demand Forecast Detail": "需求預測詳情",
"Details": "詳情",
"Schedule": "排程",
"Schedule Period": "排程期間",
"Schedule Period": "排程時期",
"Schedule Period To": "排程時期至",
"Schedule Detail": "排程詳情",
"Schedule At": "排程時間",
"Search": "搜尋",
@@ -23,7 +24,7 @@
"CODE": "編號",
"Product Count": "產品數量",
"Scheduled At": "排程時間",
"Demand Forecast Period": "需求預測期",
"Demand Forecast Period": "需求預測期",
"FG & Material Demand Forecast Detail": "成品及物料需求預測詳情",
"FG & Material Demand Forecast": "成品及物料需求預測",
"Total Estimated Demand Qty": "總預估需求量",


Ladataan…
Peruuta
Tallenna