Browse Source

[Prod Schedule] Update Detailed Prod Schedule

master
cyril.tsui 1 month ago
parent
commit
cf4155b612
7 changed files with 271 additions and 61 deletions
  1. +44
    -9
      src/app/api/scheduling/actions.ts
  2. +3
    -0
      src/app/api/scheduling/index.ts
  3. +1
    -0
      src/app/utils/formatUtil.ts
  4. +100
    -18
      src/components/DetailedScheduleDetail/DetailedScheduleDetailView.tsx
  5. +32
    -18
      src/components/DetailedScheduleDetail/ViewByFGDetails.tsx
  6. +89
    -15
      src/components/ScheduleTable/ScheduleTable.tsx
  7. +2
    -1
      src/i18n/zh/schedule.json

+ 44
- 9
src/app/api/scheduling/actions.ts View File

@@ -4,7 +4,8 @@ import { convertObjToURLSearchParams } from "@/app/utils/commonUtil";
import { serverFetchJson } from "@/app/utils/fetchUtil"; import { serverFetchJson } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api"; import { BASE_API_URL } from "@/config/api";
import { cache } from "react"; import { cache } from "react";
import { ScheduleType } from ".";
import { DetailedProdScheduleLineBomMaterialResult, DetailedProdScheduleLineResult, ScheduleType } from ".";
import { revalidateTag } from "next/cache";


export interface SearchProdSchedule { export interface SearchProdSchedule {
scheduleAt?: string; scheduleAt?: string;
@@ -31,11 +32,29 @@ export interface ProdScheduleResultByPage {
records: ProdScheduleResult[]; records: ProdScheduleResult[];
} }


export interface ReleaseDetailProdScheduleInputs {
export interface ReleaseProdScheduleInputs {
id: number; id: number;
demandQty: number; demandQty: number;
} }


export interface ReleaseProdScheduleResponse {
id: number;
code: string;
entity: {
prodScheduleLines: DetailedProdScheduleLineResult[];
};
message: string;
}

export interface SaveProdScheduleResponse {
id: number;
code: string;
entity: {
bomMaterials: DetailedProdScheduleLineBomMaterialResult[]
};
message: string;
}

export const fetchProdSchedules = cache( export const fetchProdSchedules = cache(
async (data: SearchProdSchedule | null) => { async (data: SearchProdSchedule | null) => {
const params = convertObjToURLSearchParams<SearchProdSchedule>(data); const params = convertObjToURLSearchParams<SearchProdSchedule>(data);
@@ -79,16 +98,32 @@ export const testDetailedSchedule = cache(async () => {
); );
}); });


export const releaseProdScheduleLine = cache(async (data: ReleaseDetailProdScheduleInputs) => {
return serverFetchJson(
`${BASE_API_URL}/productionSchedule/releaseLine`,
export const releaseProdScheduleLine = cache(async (data: ReleaseProdScheduleInputs) => {
const response = serverFetchJson<ReleaseProdScheduleResponse>(
`${BASE_API_URL}/productionSchedule/detail/detailed/releaseLine`,
{
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
}
);

revalidateTag("prodSchedules");

return response;
})

export const saveProdScheduleLine = cache(async (data: ReleaseProdScheduleInputs) => {
const response = serverFetchJson<SaveProdScheduleResponse>(
`${BASE_API_URL}/productionSchedule/detail/detailed/save`,
{ {
method: "POST", method: "POST",
body: JSON.stringify(data), body: JSON.stringify(data),
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
next: {
tags: ["prodSchedules"],
},
} }
)
);

revalidateTag("prodSchedules");

return response;
}) })

+ 3
- 0
src/app/api/scheduling/index.ts View File

@@ -93,8 +93,11 @@ export interface DetailedProdScheduleLineResult {
name: string; name: string;
type: string; type: string;
demandQty: number; demandQty: number;
bomOutputQty: number;
prodTimeInMinute: DetailedProdScheduleLineProdTimeResult[]; prodTimeInMinute: DetailedProdScheduleLineProdTimeResult[];
priority: number; priority: number;
approved: boolean;
proportion: number;
} }


export interface DetailedProdScheduleLineBomMaterialResult { export interface DetailedProdScheduleLineBomMaterialResult {


+ 1
- 0
src/app/utils/formatUtil.ts View File

@@ -23,6 +23,7 @@ export const moneyFormatter = new Intl.NumberFormat("en-HK", {


export const decimalFormatter = new Intl.NumberFormat("en-HK", { export const decimalFormatter = new Intl.NumberFormat("en-HK", {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2,
}); });


export const integerFormatter = new Intl.NumberFormat("en-HK", {}); export const integerFormatter = new Intl.NumberFormat("en-HK", {});


+ 100
- 18
src/components/DetailedScheduleDetail/DetailedScheduleDetailView.tsx View File

@@ -7,6 +7,7 @@ import {
FormProvider, FormProvider,
SubmitErrorHandler, SubmitErrorHandler,
SubmitHandler, SubmitHandler,
useFieldArray,
useForm, useForm,
} from "react-hook-form"; } from "react-hook-form";
import { import {
@@ -26,7 +27,10 @@ import DetailInfoCard from "@/components/DetailedScheduleDetail/DetailInfoCard";
import ViewByFGDetails, { import ViewByFGDetails, {
// FGRecord, // FGRecord,
} from "@/components/DetailedScheduleDetail/ViewByFGDetails"; } from "@/components/DetailedScheduleDetail/ViewByFGDetails";
import { DetailedProdScheduleResult, ScheduleType } from "@/app/api/scheduling";
import { DetailedProdScheduleLineResult, DetailedProdScheduleResult, ScheduleType } from "@/app/api/scheduling";
import { releaseProdScheduleLine, saveProdScheduleLine } from "@/app/api/scheduling/actions";
import useUploadContext from "../UploadProvider/useUploadContext";
import ArrowBackIcon from '@mui/icons-material/ArrowBack';


// temp interface input // temp interface input
// export interface SaveDetailedSchedule { // export interface SaveDetailedSchedule {
@@ -59,14 +63,20 @@ const DetailedScheduleDetailView: React.FC<Props> = ({
const [tabIndex, setTabIndex] = useState(0); const [tabIndex, setTabIndex] = useState(0);
const { t } = useTranslation("schedule"); const { t } = useTranslation("schedule");
const router = useRouter(); const router = useRouter();
const [isEdit, setIsEdit] = useState(false);
const [isEdit, setIsEdit] = useState(false);
const { setIsUploading } = useUploadContext()

// console.log(typeId) // console.log(typeId)
const formProps = useForm<DetailedProdScheduleResult>({ const formProps = useForm<DetailedProdScheduleResult>({
defaultValues: defaultValues defaultValues: defaultValues
}); });
const errors = formProps.formState.errors; const errors = formProps.formState.errors;


const lineFormProps = useFieldArray<DetailedProdScheduleResult>({
control: formProps.control,
name: "prodScheduleLines"
})

const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
(_e, newValue) => { (_e, newValue) => {
setTabIndex(newValue); setTabIndex(newValue);
@@ -74,6 +84,10 @@ const [isEdit, setIsEdit] = useState(false);
[], [],
); );


// const calNewProportion = useCallback((demandQty: number, bomOutputQty: number) => {
// return ((demandQty ?? 0) / (bomOutputQty ?? 1)).toFixed(2)
// }, [])

// const [pagingController, setPagingController] = useState({ // const [pagingController, setPagingController] = useState({
// pageNum: 1, // pageNum: 1,
// pageSize: 10, // pageSize: 10,
@@ -81,7 +95,7 @@ const [isEdit, setIsEdit] = useState(false);
// }); // });


const handleCancel = () => { const handleCancel = () => {
router.replace(`/scheduling/Detail`);
router.replace(`/scheduling/detailed`);
}; };


const onSubmit = useCallback<SubmitHandler<DetailedProdScheduleResult>>( const onSubmit = useCallback<SubmitHandler<DetailedProdScheduleResult>>(
@@ -106,7 +120,7 @@ const [isEdit, setIsEdit] = useState(false);


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


@@ -114,10 +128,69 @@ const [isEdit, setIsEdit] = useState(false);
setIsEdit(!isEdit); setIsEdit(!isEdit);
}; };


const onReleaseClick = useCallback(() => {
const onReleaseClick = useCallback(async (row: DetailedProdScheduleLineResult) => {
setIsUploading(true)

try {
const response = await releaseProdScheduleLine({
id: row.id,
demandQty: row.demandQty
})

if (response) {
const index = formProps.getValues("prodScheduleLines").findIndex(ele => ele.id == row.id)
// console.log(index, formProps.getValues(`prodScheduleLines.${index}.approved`))
// formProps.setValue(`prodScheduleLines.${index}.approved`, true)
// formProps.setValue(`prodScheduleLines.${index}.jobNo`, response.code)
formProps.setValue(`prodScheduleLines`, response.entity.prodScheduleLines.sort((a, b) => b.priority - a.priority))
// console.log(index, formProps.getValues(`prodScheduleLines.${index}.approved`))
}
setIsUploading(false)
} catch (e) {
console.log(e)
setIsUploading(false)
}
}, [])

const [tempValue, setTempValue] = useState<string | number | null>(null)
const onEditClick = useCallback((rowId: number) => {
const row = formProps.getValues("prodScheduleLines").find(ele => ele.id == rowId)
if (row) {
setTempValue(row.demandQty)
}
}, [])


const handleEditChange = useCallback((rowId: number, fieldName: keyof DetailedProdScheduleLineResult, newValue: number | string) => {
const index = formProps.getValues("prodScheduleLines").findIndex(ele => ele.id == rowId)
formProps.setValue(`prodScheduleLines.${index}.demandQty`, Number(newValue))
}, []) }, [])


const onSaveClick = useCallback(async (row: DetailedProdScheduleLineResult) => {
setIsUploading(true)
try {
const response = await saveProdScheduleLine({
id: row.id,
demandQty: row.demandQty
})

if (response) {
const index = formProps.getValues("prodScheduleLines").findIndex(ele => ele.id == row.id)
formProps.setValue(`prodScheduleLines.${index}.bomMaterials`, response.entity.bomMaterials)
}
setIsUploading(false)
} catch (e) {
console.log(e)
setIsUploading(false)
}
}, [])

const onCancelClick = useCallback(async (rowId: number) => {
// if (tempValue) {
const index = formProps.getValues("prodScheduleLines").findIndex(ele => ele.id == rowId)
formProps.setValue(`prodScheduleLines.${index}.demandQty`, Number(tempValue))
// }
}, [tempValue])

return ( return (
<> <>
<FormProvider {...formProps}> <FormProvider {...formProps}>
@@ -133,9 +206,10 @@ const [isEdit, setIsEdit] = useState(false);
{/*</Grid>*/} {/*</Grid>*/}
<DetailInfoCard <DetailInfoCard
// recordDetails={formProps.formState.defaultValues} // recordDetails={formProps.formState.defaultValues}
isEditing={isEdit}
// isEditing={isEdit}
isEditing={false}
/> />
<Stack
{/* <Stack
direction="row" direction="row"
justifyContent="space-between" justifyContent="space-between"
flexWrap="wrap" flexWrap="wrap"
@@ -144,13 +218,13 @@ const [isEdit, setIsEdit] = useState(false);
<Button <Button
variant="contained" variant="contained"
onClick={onClickEdit} onClick={onClickEdit}
// startIcon={<Add />}
//LinkComponent={Link}
//href="qcCategory/create"
// startIcon={<Add />}
//LinkComponent={Link}
//href="qcCategory/create"
> >
{isEdit ? t("Save") : t("Edit")} {isEdit ? t("Save") : t("Edit")}
</Button> </Button>
</Stack>
</Stack> */}


{/* <Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable"> {/* <Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable">
<Tab label={t("View By FG") + (tabIndex === 0 ? " (Selected)" : "")} iconPosition="end" /> <Tab label={t("View By FG") + (tabIndex === 0 ? " (Selected)" : "")} iconPosition="end" />
@@ -162,24 +236,32 @@ const [isEdit, setIsEdit] = useState(false);
</Typography> </Typography>
)} )}
{/* {tabIndex === 0 && <ViewByFGDetails isEdit={isEdit} apiRef={apiRef} />} */} {/* {tabIndex === 0 && <ViewByFGDetails isEdit={isEdit} apiRef={apiRef} />} */}
<ViewByFGDetails isEdit={isEdit} apiRef={apiRef} onReleaseClick={onReleaseClick} type={type}/>
<ViewByFGDetails
isEdit={true}
apiRef={apiRef}
onReleaseClick={onReleaseClick}
onEditClick={onEditClick}
handleEditChange={handleEditChange}
onSaveClick={onSaveClick}
onCancelClick={onCancelClick}
type={type} />
{/* {tabIndex === 1 && <ViewByBomDetails isEdit={isEdit} apiRef={apiRef} isHideButton={true} />} */} {/* {tabIndex === 1 && <ViewByBomDetails isEdit={isEdit} apiRef={apiRef} isHideButton={true} />} */}
<Stack direction="row" justifyContent="flex-end" gap={1}> <Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
{/* <Button
name="submit" name="submit"
variant="contained" variant="contained"
startIcon={<Check />} startIcon={<Check />}
type="submit" type="submit"
// disabled={submitDisabled}
// disabled={submitDisabled}
> >
{isEditMode ? t("Save") : t("Confirm")} {isEditMode ? t("Save") : t("Confirm")}
</Button>
</Button> */}
<Button <Button
variant="outlined" variant="outlined"
startIcon={<Close />}
startIcon={<ArrowBackIcon />}
onClick={handleCancel} onClick={handleCancel}
> >
{t("Cancel")}
{t("Back")}
</Button> </Button>
</Stack> </Stack>
</Stack> </Stack>


+ 32
- 18
src/components/DetailedScheduleDetail/ViewByFGDetails.tsx View File

@@ -23,7 +23,11 @@ type Props = {
apiRef: MutableRefObject<GridApiCommunity>; apiRef: MutableRefObject<GridApiCommunity>;
isEdit: boolean; isEdit: boolean;
type: ScheduleType; type: ScheduleType;
onReleaseClick: () => void;
onReleaseClick: (item: DetailedProdScheduleLineResult) => void;
onEditClick: (rowId: number) => void;
handleEditChange: (rowId: number, fieldName: keyof DetailedProdScheduleLineResult, newValue: number | string) => void;
onSaveClick: (item: DetailedProdScheduleLineResult) => void;
onCancelClick: (rowId: number) => void;
}; };


// export type FGRecord = { // export type FGRecord = {
@@ -35,7 +39,7 @@ type Props = {
// purchaseQty?: number; // purchaseQty?: number;
// }; // };


const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, onReleaseClick }) => {
const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, onReleaseClick, onEditClick, handleEditChange, onSaveClick, onCancelClick }) => {
const { const {
t, t,
i18n: { language }, i18n: { language },
@@ -43,8 +47,10 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, onReleaseClick


const { const {
getValues, getValues,
watch,
formState: { errors, defaultValues, touchedFields }, formState: { errors, defaultValues, touchedFields },
} = useFormContext<DetailedProdScheduleResult>(); } = useFormContext<DetailedProdScheduleResult>();

// const apiRef = useGridApiRef(); // const apiRef = useGridApiRef();


// const [pagingController, setPagingController] = useState([ // const [pagingController, setPagingController] = useState([
@@ -128,6 +134,9 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, onReleaseClick
field: "type", field: "type",
label: t("type"), label: t("type"),
type: "read-only", type: "read-only",
renderCell: (row) => {
return t(row.type);
},
// editable: true, // editable: true,
}, },
// { // {
@@ -148,7 +157,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, onReleaseClick
{ {
field: "demandQty", field: "demandQty",
label: t("Demand Qty"), label: t("Demand Qty"),
type: "input",
type: "input-number",
style: { style: {
textAlign: "right", textAlign: "right",
}, },
@@ -202,23 +211,28 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, onReleaseClick
/> />
</Grid> */} </Grid> */}
{/* {dayPeriod.map((date, index) => ( */} {/* {dayPeriod.map((date, index) => ( */}
<Grid item xs={12}>
{/* <Typography variant="overline" display="block" marginBlockEnd={1}>
<Grid item xs={12}>
{/* <Typography variant="overline" display="block" marginBlockEnd={1}>
{`${t("FG Demand Date")}: ${date}`} {`${t("FG Demand Date")}: ${date}`}
</Typography> */} </Typography> */}
<ScheduleTable<DetailedProdScheduleLineResult>
type={type}
// items={fakeRecords[index]} // Use the corresponding records for the day
items={getValues("prodScheduleLines")} // Use the corresponding records for the day
columns={columns}
// setPagingController={updatePagingController}
// pagingController={pagingController[index]}
isAutoPaging={false}
isEditable={true}
isEdit={isEdit}
hasCollapse={true}
/>
</Grid>
<ScheduleTable<DetailedProdScheduleLineResult>
type={type}
// items={fakeRecords[index]} // Use the corresponding records for the day
items={getValues("prodScheduleLines")} // Use the corresponding records for the day
columns={columns}
// setPagingController={updatePagingController}
// pagingController={pagingController[index]}
isAutoPaging={false}
isEditable={true}
isEdit={isEdit}
hasCollapse={true}
onReleaseClick={onReleaseClick}
onEditClick={onEditClick}
handleEditChange={handleEditChange}
onSaveClick={onSaveClick}
onCancelClick={onCancelClick}
/>
</Grid>
{/* ))} */} {/* ))} */}
</Grid> </Grid>
); );


+ 89
- 15
src/components/ScheduleTable/ScheduleTable.tsx View File

@@ -5,6 +5,7 @@ import React, {
DetailedHTMLProps, DetailedHTMLProps,
HTMLAttributes, HTMLAttributes,
useEffect, useEffect,
useRef,
useState, useState,
} from "react"; } from "react";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
@@ -37,6 +38,7 @@ import {
ScheduleType, ScheduleType,
} from "@/app/api/scheduling"; } from "@/app/api/scheduling";
import { defaultPagingController } from "../SearchResults/SearchResults"; import { defaultPagingController } from "../SearchResults/SearchResults";
import { useFormContext } from "react-hook-form";


export interface ResultWithId { export interface ResultWithId {
id: string | number; id: string | number;
@@ -81,6 +83,11 @@ interface Props<T extends ResultWithId> {
isEditable: boolean; isEditable: boolean;
hasCollapse: boolean; hasCollapse: boolean;
type: ScheduleType; type: ScheduleType;
onReleaseClick?: (item: T) => void;
onEditClick?: (rowId: number) => void;
handleEditChange?: (rowId: number, fieldName: keyof T, newValue: number | string) => void;
onSaveClick?: (item: T) => void;
onCancelClick?: (rowId: number) => void;
} }


function ScheduleTable<T extends ResultWithId>({ function ScheduleTable<T extends ResultWithId>({
@@ -95,15 +102,23 @@ function ScheduleTable<T extends ResultWithId>({
isEdit = false, isEdit = false,
isEditable = true, isEditable = true,
hasCollapse = false, hasCollapse = false,
onReleaseClick = undefined,
onEditClick = undefined,
handleEditChange = undefined,
onSaveClick = undefined,
onCancelClick = undefined,
}: Props<T>) { }: Props<T>) {
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10); const [rowsPerPage, setRowsPerPage] = useState(10);
const [editingRowId, setEditingRowId] = useState<number | null>(null); const [editingRowId, setEditingRowId] = useState<number | null>(null);
const [editedItems, setEditedItems] = useState<T[]>(items); const [editedItems, setEditedItems] = useState<T[]>(items);
const { t } = useTranslation("schedule"); const { t } = useTranslation("schedule");
console.log(items)

useEffect(() => { useEffect(() => {
setEditedItems(items); setEditedItems(items);
}, [items]); }, [items]);

const handleChangePage = (_event: unknown, newPage: number) => { const handleChangePage = (_event: unknown, newPage: number) => {
setPage(newPage); setPage(newPage);
if (setPagingController && pagingController) { if (setPagingController && pagingController) {
@@ -132,24 +147,42 @@ function ScheduleTable<T extends ResultWithId>({


const handleEditClick = (id: number) => { const handleEditClick = (id: number) => {
setEditingRowId(id); setEditingRowId(id);
if (onEditClick) {
onEditClick(id)
}
}; };


const handleSaveClick = (item: T) => { const handleSaveClick = (item: T) => {
setEditingRowId(null); setEditingRowId(null);
// Call API or any save logic here // Call API or any save logic here
setEditedItems((prev) =>
prev.map((row) => (row.id === item.id ? { ...row } : row)),
);
if (onSaveClick) {
onSaveClick(item)
} else {
setEditedItems((prev) =>
prev.map((row) => (row.id === item.id ? { ...row } : row)),
);
}
}; };


const handleReleaseClick = (item: T) => {
if (onReleaseClick) {
onReleaseClick(item)
}
}

const handleInputChange = ( const handleInputChange = (
id: number, id: number,
field: keyof T, field: keyof T,
value: string | number[],
// value: string | number[],
value: string | number,
) => { ) => {
setEditedItems((prev) =>
prev.map((item) => (item.id === id ? { ...item, [field]: value } : item)),
);
if (handleEditChange) {
handleEditChange(id, field, value)
} else {
setEditedItems((prev) =>
prev.map((item) => (item.id === id ? { ...item, [field]: value } : item)),
);
}
}; };


const handleDeleteClick = (id: number) => { const handleDeleteClick = (id: number) => {
@@ -157,6 +190,14 @@ function ScheduleTable<T extends ResultWithId>({
setEditedItems((prev) => prev.filter((item) => item.id !== id)); setEditedItems((prev) => prev.filter((item) => item.id !== id));
}; };


const handleCancelClick = (id: number) => {
if (onCancelClick) {
onCancelClick(id)
}

setEditingRowId(null)
}

useEffect(() => { useEffect(() => {
console.log("[debug] isEdit in table", isEdit); console.log("[debug] isEdit in table", isEdit);
//TODO: switch all record to not in edit mode and save the changes //TODO: switch all record to not in edit mode and save the changes
@@ -188,7 +229,15 @@ function ScheduleTable<T extends ResultWithId>({
<TableRow hover tabIndex={-1} key={row.id}> <TableRow hover tabIndex={-1} key={row.id}>
{isDetailedType(type) && ( {isDetailedType(type) && (
<TableCell> <TableCell>
<IconButton disabled={!isEdit}>
<IconButton
color="primary"
disabled={
// !(row as unknown as DetailedProdScheduleLineResult).bomMaterials.every(ele => (ele.availableQty ?? 0) >= (ele.demandQty ?? 0))
// ||
editingRowId === row.id
|| (row as unknown as DetailedProdScheduleLineResult).approved}
onClick={() => handleReleaseClick(row)}
>
<PlayCircleOutlineIcon /> <PlayCircleOutlineIcon />
</IconButton> </IconButton>
</TableCell> </TableCell>
@@ -208,7 +257,7 @@ function ScheduleTable<T extends ResultWithId>({
{isDetailedType(type) && isEditable && ( {isDetailedType(type) && isEditable && (
<IconButton <IconButton
disabled={!isEdit} disabled={!isEdit}
onClick={() => setEditingRowId(null)}
onClick={() => handleCancelClick(row.id as number)}
> >
<CancelIcon /> <CancelIcon />
</IconButton> </IconButton>
@@ -232,20 +281,20 @@ function ScheduleTable<T extends ResultWithId>({
<> <>
{isDetailedType(type) && isEditable && ( {isDetailedType(type) && isEditable && (
<IconButton <IconButton
disabled={!isEdit}
disabled={!isEdit || (row as unknown as DetailedProdScheduleLineResult).approved}
onClick={() => handleEditClick(row.id as number)} onClick={() => handleEditClick(row.id as number)}
> >
<EditIcon /> <EditIcon />
</IconButton> </IconButton>
)} )}
{isDetailedType(type) && isEditable && (
{/* {isDetailedType(type) && isEditable && (
<IconButton <IconButton
disabled={!isEdit} disabled={!isEdit}
onClick={() => handleDeleteClick(row.id as number)} onClick={() => handleDeleteClick(row.id as number)}
> >
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
)}
)} */}
{hasCollapse && ( {hasCollapse && (
<IconButton <IconButton
aria-label="expand row" aria-label="expand row"
@@ -286,6 +335,29 @@ function ScheduleTable<T extends ResultWithId>({
} }
/> />
); );
case "input-number":
return (
<TextField
type="number"
hiddenLabel={true}
fullWidth
defaultValue={row[columnName] as string}
onChange={(e) => {
handleInputChange(
row.id as number,
columnName,
e.target.value,
)
}}
// onChange={(e) =>
// handleInputChange(
// row.id as number,
// columnName,
// e.target.value,
// )
// }
/>
);
// case 'multi-select': // case 'multi-select':
// //TODO: May need update if use // //TODO: May need update if use
// return ( // return (
@@ -297,7 +369,9 @@ function ScheduleTable<T extends ResultWithId>({
// /> // />
// ); // );
case "read-only": case "read-only":
return <span>{row[columnName] as string}</span>;
return column.renderCell ? (
<div style={column.style}>{column.renderCell(row)}</div>
) : <span>{row[columnName] as string}</span>;
default: default:
return null; // Handle any default case if needed return null; // Handle any default case if needed
} }
@@ -330,8 +404,8 @@ function ScheduleTable<T extends ResultWithId>({
<BomMaterialTable <BomMaterialTable
type={type} type={type}
bomMaterial={ bomMaterial={
isDetailedType(type) ? (row as unknown as RoughProdScheduleLineResultByFg).bomMaterials
: (row as unknown as DetailedProdScheduleLineResult).bomMaterials
isDetailedType(type) ? (row as unknown as RoughProdScheduleLineResultByFg).bomMaterials
: (row as unknown as DetailedProdScheduleLineResult).bomMaterials
} }
/> />
</TableCell> </TableCell>


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

@@ -82,5 +82,6 @@
"mat": "物料", "mat": "物料",
"Product Count(s)": "產品數量", "Product Count(s)": "產品數量",
"Schedule Period To": "排程期間至", "Schedule Period To": "排程期間至",
"Overall": "總計"
"Overall": "總計",
"Back": "返回"
} }

Loading…
Cancel
Save