FPSMS-frontend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

257 line
8.1 KiB

  1. "use client";
  2. import {
  3. Box, Card, CardContent, Checkbox, Collapse, FormControl,
  4. FormControlLabel, Grid, Radio, RadioGroup, Stack, Tab,
  5. Tabs, TabsProps, TextField, Tooltip, Typography,
  6. } from "@mui/material";
  7. import { useFormContext, Controller, FieldPath } from "react-hook-form";
  8. import { useTranslation } from "react-i18next";
  9. import StyledDataGrid from "../StyledDataGrid";
  10. import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from "react";
  11. import {
  12. GridColDef,
  13. useGridApiContext,
  14. GridRenderEditCellParams,
  15. useGridApiRef,
  16. } from "@mui/x-data-grid";
  17. import { QcFormInput, QcResult } from "@/app/api/qc";
  18. interface Props {
  19. rows: QcResult[];
  20. disabled?: boolean;
  21. }
  22. const QcForm: React.FC<Props> = ({ rows, disabled = false }) => {
  23. const { t } = useTranslation("purchaseOrder");
  24. const apiRef = useGridApiRef();
  25. const {
  26. register,
  27. formState: { errors, defaultValues, touchedFields },
  28. watch,
  29. control,
  30. setValue,
  31. getValues,
  32. reset,
  33. resetField,
  34. setError,
  35. clearErrors,
  36. } = useFormContext<QcFormInput>();
  37. const qcDisabled = (row : QcResult) => {
  38. return disabled || isExist(row.escalationLogId);
  39. };
  40. const isExist = (data : string | number | undefined) => {
  41. return (data !== null && data !== undefined);
  42. }
  43. function BooleanEditCell(params: GridRenderEditCellParams) {
  44. const apiRef = useGridApiContext();
  45. const { id, field, value } = params;
  46. const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  47. apiRef.current.setEditCellValue({ id, field, value: e.target.checked });
  48. apiRef.current.stopCellEditMode({ id, field }); // commit immediately
  49. };
  50. return <Checkbox checked={!!value} onChange={handleChange} sx={{ p: 0 }} />;
  51. }
  52. const qcColumns: GridColDef[] = useMemo(() => [
  53. {
  54. field: "name",
  55. headerName: t("qcItem"),
  56. wrapText: true,
  57. flex: 2.5,
  58. renderCell: (params) => {
  59. const index = getRowIndex(params);//params.api.getRowIndexRelativeToVisibleRows(params.id);
  60. return (
  61. <Box
  62. sx={{
  63. lineHeight: 1.5,
  64. padding: "4px",
  65. fontSize: 18,
  66. }}
  67. >
  68. <b>{`${params.row.order ?? "N/A"}. ${params.value}`}</b><br/>
  69. {params.row.description}
  70. </Box>
  71. )},
  72. },
  73. {
  74. field: 'qcResult',
  75. headerName: t("qcResult"),
  76. flex: 1,
  77. renderCell: (params) => {
  78. const rowValue = params.row;
  79. const index = getRowIndex(params);//params.api.getRowIndexRelativeToVisibleRows(params.row.id);
  80. // const index = Number(params.id);
  81. // const index = Number(params.row.order - 1);
  82. // console.log(rowValue.row);
  83. return (
  84. <FormControl>
  85. <RadioGroup
  86. row
  87. aria-labelledby="demo-radio-buttons-group-label"
  88. // defaultValue={""}
  89. value={rowValue.qcPassed === undefined ? "" : (rowValue.qcPassed ? "true" : "false")}
  90. onChange={(e) => {
  91. const value = (e.target.value === "true");
  92. // setQcItems((prev) =>
  93. // prev.map((r): QcData => (r.id === params.id ? { ...r, qcPassed: value === "true" } : r))
  94. // );
  95. setValue(`qcResult.${index}.qcPassed`, value);
  96. }}
  97. name={`qcPassed-${params.id}`}
  98. >
  99. <FormControlLabel
  100. value="true"
  101. control={<Radio />}
  102. label="合格"
  103. disabled={qcDisabled(rowValue)}
  104. sx={{
  105. color: rowValue.qcPassed === true ? "green" : "inherit",
  106. "& .Mui-checked": {color: "green"}
  107. }}
  108. />
  109. <FormControlLabel
  110. value="false"
  111. control={<Radio />}
  112. label="不合格"
  113. disabled={qcDisabled(rowValue)}
  114. sx={{
  115. color: rowValue.qcPassed === false ? "red" : "inherit",
  116. "& .Mui-checked": {color: "red"}
  117. }}
  118. />
  119. </RadioGroup>
  120. </FormControl>
  121. );
  122. },
  123. },
  124. {
  125. field: "failQty",
  126. headerName: t("failedQty"),
  127. flex: 0.5,
  128. // editable: true,
  129. renderCell: (params) => {
  130. const index = getRowIndex(params);//params.api.getRowIndexRelativeToVisibleRows(params.id);
  131. // const index = Number(params.id);
  132. return (
  133. <TextField
  134. type="number"
  135. value={!params.row.qcPassed? params.value : '0'}
  136. disabled={params.row.qcPassed || qcDisabled(params.row)}
  137. /* TODO improve */
  138. /* Reference: https://grok.com/share/c2hhcmQtNA%3D%3D_10787069-3eec-40af-a7cc-bacbdb86bf05 */
  139. onChange={(e) => {
  140. const v = e.target.value;
  141. const next = v === '' ? undefined : Number(v);
  142. if (Number.isNaN(next)) return;
  143. setValue(`qcResult.${index}.failQty`, next);
  144. }}
  145. // onBlur={(e) => {
  146. // const v = e.target.value;
  147. // const next = v === '' ? undefined : Number(v);
  148. // if (Number.isNaN(next)) return;
  149. // setValue(`qcResult.${index}.failQty`, next);
  150. // }}
  151. onClick={(e) => e.stopPropagation()}
  152. onMouseDown={(e) => e.stopPropagation()}
  153. onKeyDown={(e) => e.stopPropagation()}
  154. inputProps={{ min: 0 }}
  155. sx={{ width: '100%',
  156. "& .MuiInputBase-input": {
  157. padding: "0.75rem",
  158. fontSize: 24,
  159. },
  160. }}
  161. />
  162. );
  163. },
  164. },
  165. {
  166. field: "remarks",
  167. headerName: t("remarks"),
  168. flex: 2,
  169. renderCell: (params) => {
  170. // const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id);
  171. const index = getRowIndex(params);//params.api.getRowIndexRelativeToVisibleRows(params.id);
  172. return (
  173. <TextField
  174. size="small"
  175. defaultValue={params.value}
  176. disabled={qcDisabled(params.row)}
  177. onBlur={(e) => {
  178. const value = e.target.value;
  179. setValue(`qcResult.${index}.remarks`, value);
  180. }}
  181. // onChange={(e) => {
  182. // const remarks = e.target.value;
  183. // // const next = v === '' ? undefined : Number(v);
  184. // // if (Number.isNaN(next)) return;
  185. // // setQcItems((prev) =>
  186. // // prev.map((r) => (r.id === params.id ? { ...r, remarks: remarks } : r))
  187. // // );
  188. // }}
  189. // {...register(`qcResult.${index}.remarks`, {
  190. // required: "remarks required!",
  191. // })}
  192. onClick={(e) => e.stopPropagation()}
  193. onMouseDown={(e) => e.stopPropagation()}
  194. onKeyDown={(e) => e.stopPropagation()}
  195. sx={{ width: '100%',
  196. "& .MuiInputBase-input": {
  197. padding: "0.75rem",
  198. fontSize: 24,
  199. },
  200. }}
  201. />
  202. );
  203. },
  204. },
  205. ], [])
  206. // const getRowId = (row :any) => {
  207. // return qcRecord.findIndex(qc => qc == row);
  208. // // return row.id || `${row.name}-${Math.random().toString(36).substr(2, 9)}`;
  209. // };
  210. const getRowHeight = (row :any) => { // Not used?
  211. console.log("row", row);
  212. if (!row.model.name) {
  213. return (row.model.name.length ?? 10) * 1.2 + 30;
  214. } else { return 60}
  215. };
  216. const getRowIndex = (params: any) => {
  217. return params.api.getRowIndexRelativeToVisibleRows(params.id);
  218. // return params.row.id;
  219. }
  220. return (
  221. <>
  222. // autoHeight
  223. <StyledDataGrid
  224. columns={qcColumns}
  225. rows={rows}
  226. sortModel={[]}
  227. getRowHeight={() => 'auto'}
  228. initialState={{
  229. pagination: { paginationModel: { page: 0, pageSize: 100 } },
  230. }}
  231. pageSizeOptions={[100]}
  232. slotProps={{
  233. pagination: {
  234. sx: {
  235. display: "none",
  236. },
  237. },
  238. }}
  239. />
  240. </>
  241. );
  242. };
  243. export default QcForm;