| @@ -1,6 +1,7 @@ | |||||
| // import { TypeEnum } from "@/app/utils/typeEnum"; | // import { TypeEnum } from "@/app/utils/typeEnum"; | ||||
| // import RoughSchedule from "@/components/RoughSchedule"; | // import RoughSchedule from "@/components/RoughSchedule"; | ||||
| // import { getServerI18n, I18nProvider } from "@/i18n"; | // import { getServerI18n, I18nProvider } from "@/i18n"; | ||||
| import { testRoughSchedule } from "@/app/api/scheduling/actions"; | |||||
| import { TypeEnum } from "../../../../app/utils/typeEnum"; | import { TypeEnum } from "../../../../app/utils/typeEnum"; | ||||
| import RoughSchedule from "../../../../components/RoughSchedule"; | import RoughSchedule from "../../../../components/RoughSchedule"; | ||||
| import { getServerI18n, I18nProvider } from "../../../../i18n"; | import { getServerI18n, I18nProvider } from "../../../../i18n"; | ||||
| @@ -22,6 +23,10 @@ const roughScheduling: React.FC = async () => { | |||||
| const type = "rough" | const type = "rough" | ||||
| // preloadClaims(); | // preloadClaims(); | ||||
| // async function testingRoughSchedule() { | |||||
| // await testRoughSchedule(); | |||||
| // } | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Stack | <Stack | ||||
| @@ -33,19 +38,18 @@ const roughScheduling: React.FC = async () => { | |||||
| <Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
| {t("Demand Forecast")} | {t("Demand Forecast")} | ||||
| </Typography> | </Typography> | ||||
| {/* <Button | {/* <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> | </Stack> | ||||
| <I18nProvider namespaces={["schedule", "common","items","project"]}> | |||||
| <I18nProvider namespaces={["schedule", "common"]}> | |||||
| <Suspense fallback={<RoughSchedule.Loading />}> | <Suspense fallback={<RoughSchedule.Loading />}> | ||||
| <RoughSchedule type={type}/> | |||||
| <RoughSchedule type={type} /> | |||||
| </Suspense> | </Suspense> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -19,6 +19,7 @@ import { arrayToDateString, decimalFormatter } from "@/app/utils/formatUtil"; | |||||
| import { isEqual, uniqBy } from "lodash"; | import { isEqual, uniqBy } from "lodash"; | ||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
| import { defaultPagingController } from "../SearchResults/SearchResults"; | import { defaultPagingController } from "../SearchResults/SearchResults"; | ||||
| import { ScheduleType } from "@/app/api/scheduling"; | |||||
| // type RecordStructure ={ | // type RecordStructure ={ | ||||
| // id: number, | // id: number, | ||||
| @@ -27,17 +28,17 @@ import { defaultPagingController } from "../SearchResults/SearchResults"; | |||||
| // }; | // }; | ||||
| type Props = { | type Props = { | ||||
| type: SearchProdSchedule["type"]; | |||||
| type: ScheduleType; | |||||
| // initProdSchedules: ProdScheduleResultByPage; | // initProdSchedules: ProdScheduleResultByPage; | ||||
| defaultInputs: SearchProdSchedule; | defaultInputs: SearchProdSchedule; | ||||
| }; | }; | ||||
| type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "type" | "pageSize" | "pageNum">>; | |||||
| type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "types" | "pageSize" | "pageNum">>; | |||||
| type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
| const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | ||||
| const [filteredSchedules, setFilteredSchedules] = useState<ProdScheduleResult[]>([]); | const [filteredSchedules, setFilteredSchedules] = useState<ProdScheduleResult[]>([]); | ||||
| const { t } = useTranslation("scheduling"); | |||||
| const { t } = useTranslation("schedule"); | |||||
| const router = useRouter(); | const router = useRouter(); | ||||
| // const [filterObj, setFilterObj] = useState({}); | // const [filterObj, setFilterObj] = useState({}); | ||||
| // const [tempSelectedValue, setTempSelectedValue] = useState({}); | // const [tempSelectedValue, setTempSelectedValue] = useState({}); | ||||
| @@ -64,12 +65,12 @@ const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | |||||
| // [router] | // [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); | console.log("[debug] record", record); | ||||
| router.push(`/scheduling/rough/edit?id=${record.id}`); | 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, | schedulePeriod: dayjs(query?.schedulePeriod).isValid() ? query?.schedulePeriod : undefined, | ||||
| schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid() ? query?.schedulePeriodTo : undefined, | schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid() ? query?.schedulePeriodTo : undefined, | ||||
| totalEstProdCount: query?.totalEstProdCount ? Number(query?.totalEstProdCount) : undefined, | totalEstProdCount: query?.totalEstProdCount ? Number(query?.totalEstProdCount) : undefined, | ||||
| type: "rough", | |||||
| types: ["rough"], | |||||
| pageNum: pagingController.pageNum - 1, | pageNum: pagingController.pageNum - 1, | ||||
| pageSize: pagingController.pageSize | pageSize: pagingController.pageSize | ||||
| } | } | ||||
| @@ -2,13 +2,14 @@ import { fetchAllItems } from "@/app/api/settings/item"; | |||||
| import { RoughScheduleLoading } from "./RoughScheduleLoading"; | import { RoughScheduleLoading } from "./RoughScheduleLoading"; | ||||
| import RSOverview from "./RoughSchedileSearchView"; | import RSOverview from "./RoughSchedileSearchView"; | ||||
| import { SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions"; | import { SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions"; | ||||
| import { ScheduleType } from "@/app/api/scheduling"; | |||||
| interface SubComponents { | interface SubComponents { | ||||
| Loading: typeof RoughScheduleLoading; | Loading: typeof RoughScheduleLoading; | ||||
| } | } | ||||
| type Props = { | type Props = { | ||||
| type: SearchProdSchedule["type"] | |||||
| type: ScheduleType | |||||
| }; | }; | ||||
| const RoughScheduleWrapper: React.FC<Props> & SubComponents = async ( | const RoughScheduleWrapper: React.FC<Props> & SubComponents = async ( | ||||
| @@ -18,7 +19,7 @@ const RoughScheduleWrapper: React.FC<Props> & SubComponents = async ( | |||||
| ) => { | ) => { | ||||
| // console.log(type) | // console.log(type) | ||||
| const defaultInputs: SearchProdSchedule = { | const defaultInputs: SearchProdSchedule = { | ||||
| type: "rough" | |||||
| types: ["rough"] | |||||
| } | } | ||||
| // const [ | // const [ | ||||
| @@ -36,14 +36,14 @@ import { useSearchParams } from "next/navigation"; | |||||
| import { decimalFormatter } from "@/app/utils/formatUtil"; | import { decimalFormatter } from "@/app/utils/formatUtil"; | ||||
| import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | ||||
| import HighlightOffIcon from '@mui/icons-material/HighlightOff'; | import HighlightOffIcon from '@mui/icons-material/HighlightOff'; | ||||
| import { ProdScheduleLineBomMaterialResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| import { RoughProdScheduleLineBomMaterialResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| interface ResultWithId { | interface ResultWithId { | ||||
| id: number; | id: number; | ||||
| } | } | ||||
| interface Props { | interface Props { | ||||
| bomMaterial: ProdScheduleLineBomMaterialResult[]; | |||||
| bomMaterial: RoughProdScheduleLineBomMaterialResult[]; | |||||
| type: ScheduleType | type: ScheduleType | ||||
| } | } | ||||
| @@ -23,7 +23,7 @@ import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; | |||||
| import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | ||||
| import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; | import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; | ||||
| import { useTranslation } from "react-i18next"; | 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 { | export interface ResultWithId { | ||||
| id: string | number; | id: string | number; | ||||
| @@ -144,10 +144,10 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| return type === "rough"; | return type === "rough"; | ||||
| } | } | ||||
| function isDetailType( | |||||
| function isDetailedType( | |||||
| type: ScheduleType | type: ScheduleType | ||||
| ): type is "detail" { | |||||
| return type === "detail"; | |||||
| ): type is "detailed" { | |||||
| return type === "detailed"; | |||||
| } | } | ||||
| function Row(props: { row: T }) { | function Row(props: { row: T }) { | ||||
| @@ -157,7 +157,7 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <TableRow hover tabIndex={-1} key={row.id}> | <TableRow hover tabIndex={-1} key={row.id}> | ||||
| {isDetailType(type) && <TableCell> | |||||
| {isDetailedType(type) && <TableCell> | |||||
| <IconButton disabled={!isEdit}> | <IconButton disabled={!isEdit}> | ||||
| <PlayCircleOutlineIcon /> | <PlayCircleOutlineIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| @@ -167,12 +167,12 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| {(editingRowId === row.id) ? ( | {(editingRowId === row.id) ? ( | ||||
| <> | <> | ||||
| { | { | ||||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}> | |||||
| isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}> | |||||
| <SaveIcon /> | <SaveIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| } | } | ||||
| { | { | ||||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}> | |||||
| isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}> | |||||
| <CancelIcon /> | <CancelIcon /> | ||||
| </IconButton> | </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)}> | onClick={() => handleEditClick(row.id as number)}> | ||||
| <EditIcon /> | <EditIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| } | } | ||||
| { | { | ||||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} | |||||
| isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} | |||||
| onClick={() => handleDeleteClick(row.id as number)}> | onClick={() => handleDeleteClick(row.id as number)}> | ||||
| <DeleteIcon /> | <DeleteIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| @@ -278,7 +278,7 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| <TableCell> | <TableCell> | ||||
| <BomMaterialTable | <BomMaterialTable | ||||
| type={type} | type={type} | ||||
| bomMaterial={(row as unknown as ProdScheduleLineResultByFg).bomMaterials} | |||||
| bomMaterial={(row as unknown as RoughProdScheduleLineResultByFg).bomMaterials} | |||||
| /> | /> | ||||
| </TableCell> | </TableCell> | ||||
| </TableRow> | </TableRow> | ||||
| @@ -298,7 +298,7 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| <Table stickyHeader> | <Table stickyHeader> | ||||
| <TableHead> | <TableHead> | ||||
| <TableRow> | <TableRow> | ||||
| {isDetailType(type) && <TableCell>{t("Release")}</TableCell>} | |||||
| {isDetailedType(type) && <TableCell>{t("Release")}</TableCell>} | |||||
| {(isEditable || hasCollapse) && <TableCell>{t("Actions")}</TableCell>} {/* Action Column Header */} | {(isEditable || hasCollapse) && <TableCell>{t("Actions")}</TableCell>} {/* Action Column Header */} | ||||
| {columns.map((column, idx) => ( | {columns.map((column, idx) => ( | ||||
| <TableCell style={column.style} key={`${column.field.toString()}${idx}`}> | <TableCell style={column.style} key={`${column.field.toString()}${idx}`}> | ||||
| @@ -196,7 +196,7 @@ function SearchBox<T extends string>({ | |||||
| <Grid key={c.paramName} item xs={6}> | <Grid key={c.paramName} item xs={6}> | ||||
| {c.type === "text" && ( | {c.type === "text" && ( | ||||
| <TextField | <TextField | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| fullWidth | fullWidth | ||||
| onChange={makeInputChangeHandler(c.paramName)} | onChange={makeInputChangeHandler(c.paramName)} | ||||
| value={inputs[c.paramName]} | value={inputs[c.paramName]} | ||||
| @@ -204,7 +204,7 @@ function SearchBox<T extends string>({ | |||||
| )} | )} | ||||
| {c.type === "multi-select" && ( | {c.type === "multi-select" && ( | ||||
| <MultiSelect | <MultiSelect | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| options={c?.options} | options={c?.options} | ||||
| selectedValues={c.filterObj?.[c.paramName] ?? []} | selectedValues={c.filterObj?.[c.paramName] ?? []} | ||||
| onChange={c.handleSelectionChange} | onChange={c.handleSelectionChange} | ||||
| @@ -213,9 +213,9 @@ function SearchBox<T extends string>({ | |||||
| )} | )} | ||||
| {c.type === "select" && ( | {c.type === "select" && ( | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <InputLabel>{c.label}</InputLabel> | |||||
| <InputLabel>{t(c.label)}</InputLabel> | |||||
| <Select | <Select | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| onChange={makeSelectChangeHandler(c.paramName)} | onChange={makeSelectChangeHandler(c.paramName)} | ||||
| value={inputs[c.paramName]} | value={inputs[c.paramName]} | ||||
| > | > | ||||
| @@ -230,9 +230,9 @@ function SearchBox<T extends string>({ | |||||
| )} | )} | ||||
| {c.type === "select-labelled" && ( | {c.type === "select-labelled" && ( | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <InputLabel>{c.label}</InputLabel> | |||||
| <InputLabel>{t(c.label)}</InputLabel> | |||||
| <Select | <Select | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| onChange={makeSelectChangeHandler(c.paramName)} | onChange={makeSelectChangeHandler(c.paramName)} | ||||
| value={inputs[c.paramName]} | value={inputs[c.paramName]} | ||||
| > | > | ||||
| @@ -312,7 +312,7 @@ function SearchBox<T extends string>({ | |||||
| </MenuItem> | </MenuItem> | ||||
| ); | ); | ||||
| }} | }} | ||||
| renderInput={(params) => <TextField {...params} variant="outlined" label={c.label} />} | |||||
| renderInput={(params) => <TextField {...params} variant="outlined" label={t(c.label)} />} | |||||
| /> | /> | ||||
| )} | )} | ||||
| {c.type === "dateRange" && ( | {c.type === "dateRange" && ( | ||||
| @@ -324,7 +324,7 @@ function SearchBox<T extends string>({ | |||||
| <Box display="flex"> | <Box display="flex"> | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <DatePicker | <DatePicker | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| onChange={makeDateChangeHandler(c.paramName)} | onChange={makeDateChangeHandler(c.paramName)} | ||||
| value={dayjs(inputs[c.paramName]).isValid() ? dayjs(inputs[c.paramName]) : null} | value={dayjs(inputs[c.paramName]).isValid() ? dayjs(inputs[c.paramName]) : null} | ||||
| /> | /> | ||||
| @@ -339,7 +339,7 @@ function SearchBox<T extends string>({ | |||||
| </Box> | </Box> | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <DatePicker | <DatePicker | ||||
| label={c.label2} | |||||
| label={c.label2 ? t(c.label2) : null} | |||||
| onChange={makeDateToChangeHandler(c.paramName)} | onChange={makeDateToChangeHandler(c.paramName)} | ||||
| value={dayjs(inputs[`${c.paramName}To`]).isValid() ? dayjs(inputs[`${c.paramName}To`]) : null} | 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"> | <Box display="flex"> | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <DatePicker | <DatePicker | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| onChange={makeDateChangeHandler(c.paramName)} | onChange={makeDateChangeHandler(c.paramName)} | ||||
| /> | /> | ||||
| </FormControl> | </FormControl> | ||||
| @@ -10,7 +10,8 @@ | |||||
| "Demand Forecast Detail": "需求預測詳情", | "Demand Forecast Detail": "需求預測詳情", | ||||
| "Details": "詳情", | "Details": "詳情", | ||||
| "Schedule": "排程", | "Schedule": "排程", | ||||
| "Schedule Period": "排程期間", | |||||
| "Schedule Period": "排程時期", | |||||
| "Schedule Period To": "排程時期至", | |||||
| "Schedule Detail": "排程詳情", | "Schedule Detail": "排程詳情", | ||||
| "Schedule At": "排程時間", | "Schedule At": "排程時間", | ||||
| "Search": "搜尋", | "Search": "搜尋", | ||||
| @@ -23,7 +24,7 @@ | |||||
| "CODE": "編號", | "CODE": "編號", | ||||
| "Product Count": "產品數量", | "Product Count": "產品數量", | ||||
| "Scheduled At": "排程時間", | "Scheduled At": "排程時間", | ||||
| "Demand Forecast Period": "需求預測期間", | |||||
| "Demand Forecast Period": "需求預測時期", | |||||
| "FG & Material Demand Forecast Detail": "成品及物料需求預測詳情", | "FG & Material Demand Forecast Detail": "成品及物料需求預測詳情", | ||||
| "FG & Material Demand Forecast": "成品及物料需求預測", | "FG & Material Demand Forecast": "成品及物料需求預測", | ||||
| "Total Estimated Demand Qty": "總預估需求量", | "Total Estimated Demand Qty": "總預估需求量", | ||||