Explorar el Código

update qc checking

master
kelvinsuen hace 4 días
padre
commit
60d588bc0a
Se han modificado 7 ficheros con 161 adiciones y 74 borrados
  1. +66
    -0
      src/components/CollapsibleCard/CollapsibleCard.tsx
  2. +1
    -0
      src/components/CollapsibleCard/index.ts
  3. +0
    -42
      src/components/DashboardPage/CollapsibleCard.tsx
  4. +8
    -2
      src/components/DashboardPage/DashboardPage.tsx
  5. +74
    -23
      src/components/PoDetail/QcComponent.tsx
  6. +8
    -5
      src/components/PoDetail/QcStockInModalVer2.tsx
  7. +4
    -2
      src/i18n/zh/purchaseOrder.json

+ 66
- 0
src/components/CollapsibleCard/CollapsibleCard.tsx Ver fichero

@@ -0,0 +1,66 @@
import React, { useState } from "react";
import {
Card,
CardHeader,
CardContent,
IconButton,
Collapse,
Checkbox,
Box,
} from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";

interface CollapsibleCardProps {
title: string;
children: React.ReactNode;
defaultOpen?: boolean;
showFilter?: boolean;
filterText?: string;
}

const CollapsibleCard: React.FC<CollapsibleCardProps> = ({
title,
children,
defaultOpen = true,
showFilter = false,
filterText = "Optional Filter",
}) => {

const [filter, setFilter] = useState(false);

const onFilterChange = (bool : boolean) => {
setFilter(bool);
setOpen(true);
}
const [open, setOpen] = useState(defaultOpen);

return (
<Card>
<CardHeader
title={title}
action={
<Box display="flex" justifyContent="flex-end" alignItems="center" gap={1}>
{showFilter && (
<>
<Checkbox
sx={{textAlign: "left"}}
checked={filter}
onChange={(e) => {onFilterChange(e.target.checked);}}
// disabled={!isEmpty(pickOrder.consoCode)}
/> <span style={{paddingRight: 20}}>{filterText}</span>
</>)}
<IconButton onClick={() => setOpen((v) => !v)}>
{open ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</IconButton>
</Box>
}
/>
<Collapse in={open}>
<CardContent>{children}</CardContent>
</Collapse>
</Card>
);
};

export default CollapsibleCard;

+ 1
- 0
src/components/CollapsibleCard/index.ts Ver fichero

@@ -0,0 +1 @@
export { default } from "./CollapsibleCard";

+ 0
- 42
src/components/DashboardPage/CollapsibleCard.tsx Ver fichero

@@ -1,42 +0,0 @@
import React, { useState } from "react";
import {
Card,
CardHeader,
CardContent,
IconButton,
Collapse,
} from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";

interface CollapsibleCardProps {
title: string;
children: React.ReactNode;
defaultOpen?: boolean;
}

const CollapsibleCard: React.FC<CollapsibleCardProps> = ({
title,
children,
defaultOpen = true,
}) => {
const [open, setOpen] = useState(defaultOpen);

return (
<Card>
<CardHeader
title={title}
action={
<IconButton onClick={() => setOpen((v) => !v)}>
{open ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</IconButton>
}
/>
<Collapse in={open}>
<CardContent>{children}</CardContent>
</Collapse>
</Card>
);
};

export default CollapsibleCard;

+ 8
- 2
src/components/DashboardPage/DashboardPage.tsx Ver fichero

@@ -13,7 +13,7 @@ import PendingStorageChart from "./chart/PendingStorageChart";
import ApplicationCompletionChart from "./chart/ApplicationCompletionChart";
import OrderCompletionChart from "./chart/OrderCompletionChart";
import DashboardBox from "./Dashboardbox";
import CollapsibleCard from "./CollapsibleCard";
import CollapsibleCard from "../CollapsibleCard";
// import SupervisorQcApproval, { IQCItems } from "./QC/SupervisorQcApproval";
import { EscalationResult } from "@/app/api/escalation";
import EscalationLogTable from "./escalation/EscalationLogTable";
@@ -28,6 +28,12 @@ const DashboardPage: React.FC<Props> = ({
}) => {
const { t } = useTranslation("dashboard");
const router = useRouter();
const [escLog, setEscLog] = useState<EscalationResult[]>([])
useEffect(() => {
setEscLog(escalationLogs);
}, [escalationLogs])

return (
<ThemeProvider theme={theme}>
@@ -35,7 +41,7 @@ const DashboardPage: React.FC<Props> = ({
<Grid item xs={12}>
<CollapsibleCard title={t("My Escalation List")}>
<CardContent>
<EscalationLogTable items={escalationLogs || []}/>
<EscalationLogTable items={escLog}/>
</CardContent>
</CollapsibleCard>
</Grid>


+ 74
- 23
src/components/PoDetail/QcComponent.tsx Ver fichero

@@ -20,7 +20,7 @@ import {
Tooltip,
Typography,
} from "@mui/material";
import { useFormContext, Controller, FieldPath, useFieldArray } from "react-hook-form";
import { useFormContext, Controller, FieldPath } from "react-hook-form";
import { useTranslation } from "react-i18next";
import StyledDataGrid from "../StyledDataGrid";
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from "react";
@@ -51,11 +51,12 @@ import QcDataGrid from "./QCDatagrid";
import StockInFormVer2 from "./StockInFormVer2";
import { dummyEscalationHistory, dummyQCData } from "./dummyQcTemplate";
import { ModalFormInput } from "@/app/api/po/actions";
import { escape } from "lodash";
import { escape, min } from "lodash";
import { PanoramaSharp } from "@mui/icons-material";
import EscalationLogTable from "../DashboardPage/escalation/EscalationLogTable";
import { EscalationResult } from "@/app/api/escalation";
import { EscalationCombo } from "@/app/api/user";
import CollapsibleCard from "../CollapsibleCard/CollapsibleCard";

interface Props {
itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] };
@@ -135,16 +136,20 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala
const accQty = watch("acceptQty");
const validateForm = useCallback(() => {
if (qcDecision == 1) {
if (accQty > itemDetail.acceptedQty){
if (isNaN(accQty) || accQty === undefined || accQty === null || typeof(accQty) != "number") {
setError("acceptQty", { message: t("value must be a number") });
} else
if (!Number.isInteger(accQty)) {
setError("acceptQty", { message: t("value must be integer") });
}
if (accQty > itemDetail.acceptedQty) {
setError("acceptQty", { message: `${t("acceptQty must not greater than")} ${
itemDetail.acceptedQty}` });
}
if (accQty < 1){
} else
if (accQty < 1) {
setError("acceptQty", { message: t("minimal value is 1") });
}
if (isNaN(accQty)){
setError("acceptQty", { message: t("value must be a number") });
}
} else
console.log("%c Validated accQty:", "color:yellow", accQty);
}
},[setError, qcDecision, accQty, itemDetail])

@@ -343,7 +348,6 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala
onClick={(e) => e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
onKeyDown={(e) => e.stopPropagation()}
inputProps={{ min: 0 }}
sx={{ width: '100%' }}
/>
);
@@ -490,7 +494,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala
</Grid> */}
<Grid item xs={12}>
<EscalationLogTable type="qc" items={itemDetail.escResult || []}/>
{/* <Collapse in={true}> */}
<CollapsibleCard title={t("QC Record")}>
<StyledDataGrid
columns={qcColumns}
rows={qcResult}
@@ -499,7 +503,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala
autoHeight
sortModel={[]}
/>
{/* </Collapse> */}
</CollapsibleCard>
{/* <StyledDataGrid
rows={escalationHistory}
columns={columns}
@@ -531,37 +535,84 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala
// value={field.value?.toString() || "true"}
onChange={(e) => {
const value = e.target.value.toString();// === 'true';
if (value != "1" && Boolean(errors.acceptQty)) {
// if (!value && Boolean(errors.acceptQty)) {
setValue("acceptQty", itemDetail.acceptedQty ?? 0);

const input = document.getElementById('accQty') as HTMLInputElement;
console.log("%c Error", "color:pink", errors.acceptQty);
if (input) { // Selected Reject in new flow with Error
if (value == "1") { // Selected Accept
input.value = Number(accQty).toString();
} else {
if (Boolean(errors.acceptQty)) {
setValue("acceptQty", 0);
}
input.value = '0';
}
}
// setValue("acceptQty", itemDetail.acceptedQty ?? 0);
// clearErrors("acceptQty");
// }
field.onChange(value);
}}
>
<FormControlLabel disabled={disabled}
value="1" control={<Radio />} label="接受來貨" />
{(itemDetail.status == "escalated" || (disabled && accQty != itemDetail.acceptedQty && qcDecision == 1)) && ( //TODO Improve
{(itemDetail.status == "escalated"|| (disabled && accQty != itemDetail.acceptedQty && qcDecision == 1)) && ( //TODO Improve
<Box sx={{mr:2}}>
<TextField
type="number"
// type="number"
id="accQty"
label={t("acceptQty")}
sx={{ width: '150px' }}
value={(qcDecision == 1)? Number(accQty) : 0 }
// value={Number(accQty)}
defaultValue={Number(accQty)}
// defaultValue={(qcDecision == 1)? Number(accQty) : 0}
// value={(qcDecision == 1)? Number(accQty) : undefined }
// value={qcAccept? accQty : 0 }
disabled={qcDecision != 1 || disabled}
// disabled={!qcAccept || disabled}
{...register("acceptQty", {
required: "acceptQty required!",
})}
onBlur={(e) => {
const value = e.target.value;
const input = document.getElementById('accQty') as HTMLInputElement;
input.value = Number(value).toString()
setValue(`acceptQty`, Number(value));
}}
onInput={(e: React.ChangeEvent<HTMLInputElement>) => {
const input = e.target.value;

const numReg = /^[0-9]+$/
let r = '';
if (!numReg.test(input)) {
const result = input.replace(/\D/g, "");
r = (result === '' ? result : Number(result)).toString();
} else {
r = Number(input).toString()
}
e.target.value = r;
}}
inputProps={{ min: 1, max:itemDetail.acceptedQty }}
// onChange={(e) => {
// const inputValue = e.target.value;
// if (inputValue === '' || /^[0-9]*$/.test(inputValue)) {
// setValue("acceptQty", Number(inputValue === '' ? null : parseInt(inputValue, 10)));
// }
// }}
// {...register("acceptQty", {
// required: "acceptQty required!",
// })}
error={Boolean(errors.acceptQty)}
helperText={errors.acceptQty?.message}
/>
/>
<TextField
type="number"
label={t("rejectQty")}
sx={{ width: '150px' }}
value={itemDetail.acceptedQty - accQty}
value={
(!Boolean(errors.acceptQty)) ?
(qcDecision == 1 ? itemDetail.acceptedQty - accQty : itemDetail.acceptedQty)
: ""
}
error={Boolean(errors.acceptQty)}
disabled={true}
/>
</Box>)}


+ 8
- 5
src/components/PoDetail/QcStockInModalVer2.tsx Ver fichero

@@ -218,7 +218,7 @@ const [qcItems, setQcItems] = useState(dummyQCData)
// Get QC data from the shared form context
const qcAccept = data.qcDecision == 1;
// const qcAccept = data.qcAccept;
const acceptQty = Number(data.acceptQty);
let acceptQty = Number(data.acceptQty);
const qcResults = data.qcResult || dummyQCData; // qcItems;
// const qcResults = data.qcResult as PurchaseQcResult[]; // qcItems;
// const qcResults = viewOnly? data.qcResult as PurchaseQcResult[] : qcItems;
@@ -241,12 +241,15 @@ const [qcItems, setQcItems] = useState(dummyQCData)
// if (qcAccept === undefined) {
validationErrors.push(t("QC decision is required"));
}
// Check if accept quantity is valid
if (acceptQty === undefined || acceptQty <= 0) {
validationErrors.push("Accept quantity must be greater than 0");
if (data.qcDecision == 2) {
acceptQty = 0;
} else {
if (acceptQty === undefined || acceptQty <= 0) {
validationErrors.push("Accept quantity must be greater than 0");
}
}

// Check if dates are input
if (data.productionDate === undefined || data.productionDate == null) {
alert("請輸入生產日期!");


+ 4
- 2
src/i18n/zh/purchaseOrder.json Ver fichero

@@ -78,7 +78,7 @@
"status": "狀態",
"acceptedQty must not greater than": "接受數量不得大於",
"minimal value is 1": "最小值為1",
"value must be a number": "值必須是數字",
"value must be a number": "請輸入數字",
"qc Check": "質量控制檢查",
"Please select QC": "請選擇質量控制",
"failQty": "失敗數量",
@@ -142,5 +142,7 @@
"Select All": "選擇全部採購單",
"View Selected": "查看已選擇採購單",
"No Option": "沒有選項",
"receivedTotal": "已來貨總數"
"receivedTotal": "已來貨總數",
"QC Record": "品檢記錄",
"value must be integer": "請輸入整數"
}

Cargando…
Cancelar
Guardar