@@ -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": "總預估需求量", | ||||