| @@ -20,7 +20,7 @@ export interface QcData { | |||
| qcItemId: number, | |||
| code: string, | |||
| name: string, | |||
| qcDescription: string, | |||
| description: string, | |||
| qcPassed: boolean | undefined | |||
| failQty: number | undefined | |||
| remarks: string | undefined | |||
| @@ -4,8 +4,4 @@ | |||
| html, body { | |||
| overscroll-behavior: none; | |||
| } | |||
| .swal2-custom-zindex { | |||
| z-index: 10000 !important; | |||
| } | |||
| @@ -229,7 +229,9 @@ const PutAwayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled, setRowM | |||
| flex: 0.2, | |||
| editable: false, | |||
| renderCell(params) { | |||
| return `${params.api.getRowIndexRelativeToVisibleRows(params.id) + 1}.` | |||
| return <span style={{fontSize:18}}> | |||
| {`${params.api.getRowIndexRelativeToVisibleRows(params.id) + 1}.`} | |||
| </span> | |||
| }, | |||
| }, | |||
| { | |||
| @@ -238,7 +240,9 @@ const PutAwayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled, setRowM | |||
| flex: 1, | |||
| editable: false, | |||
| renderCell(params) { | |||
| return `${(arrayToDateTimeString(params.value))}`; | |||
| return <span style={{fontSize:24}}> | |||
| {`${(arrayToDateTimeString(params.value))}`} | |||
| </span> | |||
| }, | |||
| }, | |||
| { | |||
| @@ -246,6 +250,11 @@ const PutAwayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled, setRowM | |||
| headerName: t("putawayUser"), | |||
| flex: 1, | |||
| editable: false, | |||
| renderCell(params) { | |||
| return <span style={{fontSize:24}}> | |||
| {params.value} | |||
| </span> | |||
| } | |||
| }, | |||
| { | |||
| field: "qty", | |||
| @@ -254,38 +263,55 @@ const PutAwayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled, setRowM | |||
| editable: false, | |||
| headerAlign: "right", | |||
| align: "right", | |||
| renderCell(params) { | |||
| return <span style={{fontSize:24}}> | |||
| {params.value} | |||
| </span> | |||
| } | |||
| }, | |||
| { | |||
| field: "warehouse", | |||
| headerName: t("warehouse"), | |||
| flex: 2, | |||
| editable: false, | |||
| renderEditCell: (params) => { | |||
| const index = params.api.getRowIndexRelativeToVisibleRows(params.row.id) | |||
| // console.log(index) | |||
| // console.log(watch(`putAwayLines.${index}.warehouse`)) | |||
| return <Autocomplete | |||
| fullWidth | |||
| disableClearable | |||
| options={options} | |||
| // defaultValue={options.find((o) => o.value === itemDetail.defaultWarehouseId)} | |||
| // value={options.find((o) => o.value === watch(`putAwayLines.${index}.warehouseId`))} | |||
| defaultValue={options.find((o) => o.value === watch(`putAwayLines.${index}.warehouseId`))} | |||
| onChange={(event, value) => { | |||
| params.api.setEditCellValue({ id: params.id, field: params.field, value: options.find((o) => o.value === value.value)?.label ?? ""}) | |||
| params.api.setEditCellValue({ id: params.id, field: "warehouseId", value: value.value}) | |||
| // setValue(`putAwayLines.${index}.warehouseId`, value.value) | |||
| // setValue(`putAwayLines.${index}.warehouse`, options.find((o) => o.value === value.value)?.label ?? "") | |||
| }} | |||
| renderInput={(params) => ( | |||
| <TextField | |||
| {...params} | |||
| variant="outlined" | |||
| // label={t("Warehouse")} | |||
| /> | |||
| )} | |||
| /> | |||
| renderCell(params) { | |||
| return <span style={{fontSize:24}}> | |||
| {params.value} | |||
| </span> | |||
| } | |||
| // renderEditCell: (params) => { | |||
| // const index = params.api.getRowIndexRelativeToVisibleRows(params.row.id) | |||
| // // console.log(index) | |||
| // // console.log(watch(`putAwayLines.${index}.warehouse`)) | |||
| // return <Autocomplete | |||
| // fullWidth | |||
| // disableClearable | |||
| // options={options} | |||
| // // defaultValue={options.find((o) => o.value === itemDetail.defaultWarehouseId)} | |||
| // // value={options.find((o) => o.value === watch(`putAwayLines.${index}.warehouseId`))} | |||
| // defaultValue={options.find((o) => o.value === watch(`putAwayLines.${index}.warehouseId`))} | |||
| // onChange={(event, value) => { | |||
| // params.api.setEditCellValue({ id: params.id, field: params.field, value: options.find((o) => o.value === value.value)?.label ?? ""}) | |||
| // params.api.setEditCellValue({ id: params.id, field: "warehouseId", value: value.value}) | |||
| // // setValue(`putAwayLines.${index}.warehouseId`, value.value) | |||
| // // setValue(`putAwayLines.${index}.warehouse`, options.find((o) => o.value === value.value)?.label ?? "") | |||
| // }} | |||
| // sx={{ | |||
| // // Style the dropdown options | |||
| // "& .MuiAutocomplete-option": { | |||
| // fontSize: 24, | |||
| // }, | |||
| // }} | |||
| // renderInput={(params) => ( | |||
| // <TextField | |||
| // {...params} | |||
| // variant="outlined" | |||
| // InputProps={{style: {fontSize: 24}}} | |||
| // // label={t("Warehouse")} | |||
| // /> | |||
| // )} | |||
| // /> | |||
| // } | |||
| // renderCell(params) { | |||
| // return <>{filteredWarehouse[0].name}</> | |||
| // }, | |||
| @@ -237,10 +237,10 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| const qcColumns: GridColDef[] = useMemo(() => [ | |||
| { | |||
| field: "code", | |||
| field: "name", | |||
| headerName: t("qcItem"), | |||
| wrapText: true, | |||
| flex: 2, | |||
| flex: 2.5, | |||
| renderCell: (params) => { | |||
| const index = params.api.getRowIndexRelativeToVisibleRows(params.id) + 1; | |||
| return ( | |||
| @@ -248,17 +248,18 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| sx={{ | |||
| lineHeight: 1.5, | |||
| padding: "4px", | |||
| fontSize: 18, | |||
| }} | |||
| > | |||
| <b>{`${index}. ${params.value}`}</b><br/> | |||
| {params.row.name} | |||
| {params.row.description} | |||
| </Box> | |||
| )}, | |||
| }, | |||
| { | |||
| field: 'qcResult', | |||
| headerName: t("qcResult"), | |||
| flex: 1.5, | |||
| flex: 1, | |||
| renderCell: (params) => { | |||
| const rowValue = params.row; | |||
| const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id); | |||
| @@ -307,14 +308,13 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| { | |||
| field: "failQty", | |||
| headerName: t("failedQty"), | |||
| flex: 1, | |||
| flex: 0.5, | |||
| // editable: true, | |||
| renderCell: (params) => { | |||
| const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id); | |||
| return ( | |||
| <TextField | |||
| type="number" | |||
| size="small" | |||
| value={!params.row.qcPassed? params.value : '0'} | |||
| disabled={params.row.qcPassed || qcDisabled(params.row)} | |||
| /* TODO improve */ | |||
| @@ -335,7 +335,12 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| onMouseDown={(e) => e.stopPropagation()} | |||
| onKeyDown={(e) => e.stopPropagation()} | |||
| inputProps={{ min: 0 }} | |||
| sx={{ width: '100%' }} | |||
| sx={{ width: '100%', | |||
| "& .MuiInputBase-input": { | |||
| padding: "0.75rem", | |||
| fontSize: 24, | |||
| }, | |||
| }} | |||
| /> | |||
| ); | |||
| }, | |||
| @@ -369,7 +374,12 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| onClick={(e) => e.stopPropagation()} | |||
| onMouseDown={(e) => e.stopPropagation()} | |||
| onKeyDown={(e) => e.stopPropagation()} | |||
| sx={{ width: '100%' }} | |||
| sx={{ width: '100%', | |||
| "& .MuiInputBase-input": { | |||
| padding: "0.75rem", | |||
| fontSize: 24, | |||
| }, | |||
| }} | |||
| /> | |||
| ); | |||
| }, | |||
| @@ -54,6 +54,35 @@ type EntryError = | |||
| // type PoQcRow = TableRow<Partial<PurchaseQcResult>, EntryError>; | |||
| const textfieldSx = { | |||
| width: "100%", | |||
| "& .MuiInputBase-root": { | |||
| // height: "120", // Scales with root font size | |||
| height: "5rem", // Scales with root font size | |||
| }, | |||
| "& .MuiInputBase-input": { | |||
| height: "100%", | |||
| boxSizing: "border-box", | |||
| padding: "0.75rem", | |||
| fontSize: 24, | |||
| }, | |||
| "& .MuiInputLabel-root": { | |||
| fontSize: 24, | |||
| transform: "translate(14px, 1.5rem) scale(1)", | |||
| "&.MuiInputLabel-shrink": { | |||
| fontSize: 18, | |||
| transform: "translate(14px, -9px) scale(1)", | |||
| }, | |||
| // [theme.breakpoints.down("sm")]: { | |||
| // fontSize: "1rem", | |||
| // transform: "translate(14px, 1.5rem) scale(1)", | |||
| // "&.MuiInputLabel-shrink": { | |||
| // fontSize: "0.875rem", | |||
| // }, | |||
| // }, | |||
| }, | |||
| }; | |||
| const StockInForm: React.FC<Props> = ({ | |||
| // qc, | |||
| itemDetail, | |||
| @@ -136,6 +165,7 @@ const StockInForm: React.FC<Props> = ({ | |||
| {...register("dnNo", { | |||
| // required: "productLotNo required!", | |||
| })} | |||
| sx={textfieldSx} | |||
| disabled={disabled} | |||
| // error={Boolean(errors.productLotNo)} | |||
| // helperText={errors.productLotNo?.message} | |||
| @@ -148,6 +178,7 @@ const StockInForm: React.FC<Props> = ({ | |||
| {...register("itemName", { | |||
| // required: "productLotNo required!", | |||
| })} | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| // error={Boolean(errors.productLotNo)} | |||
| // helperText={errors.productLotNo?.message} | |||
| @@ -160,6 +191,7 @@ const StockInForm: React.FC<Props> = ({ | |||
| {...register("poCode", { | |||
| // required: "productLotNo required!", | |||
| })} | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| // error={Boolean(errors.productLotNo)} | |||
| // helperText={errors.productLotNo?.message} | |||
| @@ -180,7 +212,7 @@ const StockInForm: React.FC<Props> = ({ | |||
| > | |||
| <DatePicker | |||
| {...field} | |||
| sx={{ width: "100%" }} | |||
| sx={textfieldSx} | |||
| label={t("receiptDate")} | |||
| value={dayjs(watch("receiptDate"))} | |||
| disabled={true} | |||
| @@ -210,6 +242,7 @@ const StockInForm: React.FC<Props> = ({ | |||
| {...register("supplier", { | |||
| // required: "productLotNo required!", | |||
| })} | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| /> | |||
| </Grid> | |||
| @@ -222,51 +255,52 @@ const StockInForm: React.FC<Props> = ({ | |||
| {...register("productLotNo", { | |||
| // required: "productLotNo required!", | |||
| })} | |||
| sx={textfieldSx} | |||
| disabled={disabled} | |||
| error={Boolean(errors.productLotNo)} | |||
| helperText={errors.productLotNo?.message} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <Controller | |||
| control={control} | |||
| name="productionDate" | |||
| // rules={{ required: !Boolean(expiryDate) }} | |||
| render={({ field }) => { | |||
| return ( | |||
| <LocalizationProvider | |||
| dateAdapter={AdapterDayjs} | |||
| adapterLocale={`${language}-hk`} | |||
| > | |||
| <DatePicker | |||
| {...field} | |||
| sx={{ width: "100%" }} | |||
| label={t("productionDate")} | |||
| value={productionDate ? dayjs(productionDate) : undefined} | |||
| disabled={disabled} | |||
| onChange={(date) => { | |||
| if (!date) return; | |||
| setValue( | |||
| "productionDate", | |||
| date.format(INPUT_DATE_FORMAT), | |||
| ); | |||
| // field.onChange(date); | |||
| }} | |||
| inputRef={field.ref} | |||
| slotProps={{ | |||
| textField: { | |||
| // required: true, | |||
| error: Boolean(errors.productionDate?.message), | |||
| helperText: errors.productionDate?.message, | |||
| }, | |||
| }} | |||
| /> | |||
| </LocalizationProvider> | |||
| ); | |||
| }} | |||
| /> | |||
| </Grid> | |||
| {putawayMode || ( | |||
| {putawayMode || (<> | |||
| <Grid item xs={6}> | |||
| <Controller | |||
| control={control} | |||
| name="productionDate" | |||
| // rules={{ required: !Boolean(expiryDate) }} | |||
| render={({ field }) => { | |||
| return ( | |||
| <LocalizationProvider | |||
| dateAdapter={AdapterDayjs} | |||
| adapterLocale={`${language}-hk`} | |||
| > | |||
| <DatePicker | |||
| {...field} | |||
| sx={textfieldSx} | |||
| label={t("productionDate")} | |||
| value={productionDate ? dayjs(productionDate) : undefined} | |||
| disabled={disabled} | |||
| onChange={(date) => { | |||
| if (!date) return; | |||
| setValue( | |||
| "productionDate", | |||
| date.format(INPUT_DATE_FORMAT), | |||
| ); | |||
| // field.onChange(date); | |||
| }} | |||
| inputRef={field.ref} | |||
| slotProps={{ | |||
| textField: { | |||
| // required: true, | |||
| error: Boolean(errors.productionDate?.message), | |||
| helperText: errors.productionDate?.message, | |||
| }, | |||
| }} | |||
| /> | |||
| </LocalizationProvider> | |||
| ); | |||
| }} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("qty")} | |||
| @@ -274,9 +308,10 @@ const StockInForm: React.FC<Props> = ({ | |||
| {...register("qty", { | |||
| required: "qty required!", | |||
| })} | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| /> | |||
| </Grid> | |||
| </Grid></> | |||
| )} | |||
| <Grid item xs={6}> | |||
| <Controller | |||
| @@ -291,7 +326,7 @@ const StockInForm: React.FC<Props> = ({ | |||
| > | |||
| <DatePicker | |||
| {...field} | |||
| sx={{ width: "100%" }} | |||
| sx={textfieldSx} | |||
| label={t("expiryDate")} | |||
| value={expiryDate ? dayjs(expiryDate) : undefined} | |||
| disabled={disabled} | |||
| @@ -323,6 +358,7 @@ const StockInForm: React.FC<Props> = ({ | |||
| {...register("receivedQty", { | |||
| required: "receivedQty required!", | |||
| })} | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| /> | |||
| </Grid> | |||
| @@ -331,33 +367,47 @@ const StockInForm: React.FC<Props> = ({ | |||
| <TextField | |||
| label={t("uom")} | |||
| fullWidth | |||
| {...register("uom.code", { | |||
| {...register("uom.udfudesc", { | |||
| required: "uom required!", | |||
| })} | |||
| // value={uom?.code} | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| /> | |||
| </Grid> | |||
| {putawayMode ? ( | |||
| {putawayMode ? (<> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={`${t("processedQty")} / ${t("acceptedQty")}`} | |||
| label={t("acceptedQty")} | |||
| fullWidth | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| value={ | |||
| `${itemDetail.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0} / ${itemDetail.acceptedQty}` | |||
| } | |||
| value={itemDetail.acceptedQty} | |||
| // disabled={true} | |||
| // disabled={disabled} | |||
| // error={Boolean(errors.acceptedQty)} | |||
| // helperText={errors.acceptedQty?.message} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("processedQty")} | |||
| fullWidth | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| value={itemDetail.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0} | |||
| // disabled={true} | |||
| // disabled={disabled} | |||
| // error={Boolean(errors.acceptedQty)} | |||
| // helperText={errors.acceptedQty?.message} | |||
| /> | |||
| </Grid></> | |||
| ) : ( | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("acceptedQty")} | |||
| fullWidth | |||
| sx={textfieldSx} | |||
| disabled={true} | |||
| {...register("acceptedQty", { | |||
| required: "acceptedQty required!", | |||
| @@ -15,8 +15,8 @@ export const dummyQCData: QcData[] = [ | |||
| id: 1, | |||
| qcItemId: 4, | |||
| code: "包裝", | |||
| qcDescription: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | |||
| name: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | |||
| description: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | |||
| name: "包裝", | |||
| qcPassed: undefined, | |||
| failQty: undefined, | |||
| remarks: undefined, | |||
| @@ -25,8 +25,8 @@ export const dummyQCData: QcData[] = [ | |||
| id: 2, | |||
| qcItemId: 5, | |||
| code: "肉質", | |||
| qcDescription: "肉質鬆散,則不合格", | |||
| name: "肉質鬆散,則不合格", | |||
| description: "肉質鬆散,則不合格", | |||
| name: "肉質", | |||
| qcPassed: undefined, | |||
| failQty: undefined, | |||
| remarks: undefined, | |||
| @@ -35,8 +35,8 @@ export const dummyQCData: QcData[] = [ | |||
| id: 3, | |||
| qcItemId: 6, | |||
| code: "顔色", | |||
| qcDescription: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", | |||
| name: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", | |||
| description: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", | |||
| name: "顔色", | |||
| qcPassed: undefined, | |||
| failQty: undefined, | |||
| remarks: undefined, | |||
| @@ -45,8 +45,8 @@ export const dummyQCData: QcData[] = [ | |||
| id: 4, | |||
| qcItemId: 7, | |||
| code: "狀態", | |||
| qcDescription: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | |||
| name: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | |||
| description: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | |||
| name: "狀態", | |||
| qcPassed: undefined, | |||
| failQty: undefined, | |||
| remarks: undefined, | |||
| @@ -55,8 +55,8 @@ export const dummyQCData: QcData[] = [ | |||
| id: 5, | |||
| qcItemId: 8, | |||
| code: "異物", | |||
| qcDescription: "有不屬於本食材的雜質,則不合格", | |||
| name: "有不屬於本食材的雜質,則不合格", | |||
| description: "有不屬於本食材的雜質,則不合格", | |||
| name: "異物", | |||
| qcPassed: undefined, | |||
| failQty: undefined, | |||
| remarks: undefined, | |||
| @@ -150,10 +150,37 @@ const components: ThemeOptions["components"] = { | |||
| width: "100%", | |||
| zIndex: 2000, | |||
| }, | |||
| ".swal2-custom-zindex": { | |||
| zIndex: 10000, // Set z-index for SweetAlert2 modals | |||
| }, | |||
| }, | |||
| }, | |||
| MuiInputBase: { | |||
| styleOverrides: { | |||
| root: { | |||
| "&:not(.Mui-disabled)": { | |||
| backgroundColor: "rgba(200, 230, 255, 0.2)", // Slightly cyan-ish background | |||
| "&:hover": { | |||
| backgroundColor: "rgba(200, 230, 255, 0.25)", // Slightly darker on hover | |||
| }, | |||
| "&.Mui-focused": { | |||
| backgroundColor: "rgba(200, 230, 255, 0.3)", // More pronounced on focus | |||
| }, | |||
| }, | |||
| "&.Mui-disabled": { | |||
| backgroundColor: "#ffffff", // White background | |||
| opacity: 1, // Remove MUI's default opacity reduction | |||
| "& .MuiInputBase-input": { | |||
| color: "#000", // Black text | |||
| cursor: "default", // Default cursor | |||
| WebkitTextFillColor: "#000", // Ensure text color isn't grayed out in WebKit browsers | |||
| }, | |||
| "& fieldset": { | |||
| backgroundColor: "transparent", // Ensure no extra background effects | |||
| boxShadow: "none", // Remove any box-shadow | |||
| }, | |||
| }, | |||
| }, | |||
| input: { | |||
| "&::placeholder": { | |||
| opacity: 1, | |||
| @@ -244,6 +271,17 @@ const components: ThemeOptions["components"] = { | |||
| boxShadow: `${palette.error.main} 0 0 0 2px`, | |||
| }, | |||
| }, | |||
| "&:not(.Mui-disabled)": { | |||
| "&:hover .MuiOutlinedInput-notchedOutline": { | |||
| borderColor: "rgba(0, 0, 0, 0.6)", // Darker border on hover | |||
| }, | |||
| "&.Mui-focused .MuiOutlinedInput-notchedOutline": { | |||
| borderColor: "rgba(0, 0, 0, 0.7)", // Darkest border when focused | |||
| }, | |||
| }, | |||
| "&.Mui-disabled .MuiOutlinedInput-notchedOutline": { | |||
| border: "1px solid #ccc", // Simple gray border for disabled | |||
| }, | |||
| }, | |||
| input: { | |||
| fontSize: defaultFontSize, | |||
| @@ -278,6 +316,13 @@ const components: ThemeOptions["components"] = { | |||
| background: palette.primary.contrastText, | |||
| }, | |||
| }, | |||
| "&.Mui-disabled": { | |||
| color: "rgba(0, 0, 0, 0.6)", // Black label | |||
| transform: "translate(14px, 16px) scale(1)", // Position like placeholder | |||
| "&.Mui-focused": { | |||
| transform: "translate(14px, 16px) scale(1)", // Keep label in place when "focused" | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||