CANCERYS\kw093 3 недель назад
Родитель
Сommit
6daea70c21
7 измененных файлов: 53 добавлений и 40 удалений
  1. +3
    -0
      src/app/api/jo/actions.ts
  2. +14
    -19
      src/components/ProductionProcess/JobProcessStatus.tsx
  3. +1
    -1
      src/components/ProductionProcess/ProductionProcessList.tsx
  4. +19
    -17
      src/components/StockIn/FgStockInForm.tsx
  5. +7
    -2
      src/config/authConfig.ts
  6. +6
    -1
      src/i18n/zh/common.json
  7. +3
    -0
      src/i18n/zh/jo.json

+ 3
- 0
src/app/api/jo/actions.ts Просмотреть файл

@@ -1208,6 +1208,9 @@ export interface JobProcessStatusResponse {
jobOrderCode: string; jobOrderCode: string;
itemCode: string; itemCode: string;
itemName: string; itemName: string;
processingTime: number | null;
setupTime: number | null;
changeoverTime: number | null;
planEndTime?: string | null; planEndTime?: string | null;
processes: ProcessStatusInfo[]; processes: ProcessStatusInfo[];
} }


+ 14
- 19
src/components/ProductionProcess/JobProcessStatus.tsx Просмотреть файл

@@ -99,18 +99,16 @@ const JobProcessStatus: React.FC = () => {
return '-'; return '-';
}; };


const calculateRemainingTime = (planEndTime: any): string => {
const calculateRemainingTime = (planEndTime: any, processingTime: number | null, setupTime: number | null, changeoverTime: number | null): string => {
if (!planEndTime) return '-'; if (!planEndTime) return '-';
let endTime: dayjs.Dayjs; let endTime: dayjs.Dayjs;
// Handle array format [year, month, day, hour, minute, second] // Handle array format [year, month, day, hour, minute, second]
// 使用与 OverallTimeRemainingCard 相同的方式处理
// Use arrayToDayjs for consistency with other parts of the codebase
if (Array.isArray(planEndTime)) { if (Array.isArray(planEndTime)) {
try { try {
const [year, month, day, hour = 0, minute = 0, second = 0] = planEndTime;
// 注意:JavaScript Date 构造函数中月份是 0-based,所以需要 month - 1
endTime = dayjs(new Date(year, month - 1, day, hour, minute, second));
endTime = arrayToDayjs(planEndTime, true);
console.log('Parsed planEndTime array:', { console.log('Parsed planEndTime array:', {
array: planEndTime, array: planEndTime,
parsed: endTime.format('YYYY-MM-DD HH:mm:ss'), parsed: endTime.format('YYYY-MM-DD HH:mm:ss'),
@@ -143,6 +141,7 @@ const JobProcessStatus: React.FC = () => {
diffMinutes: diff diffMinutes: diff
}); });
// If the planned end time is in the past, show 0 (or you could show negative time)
if (diff < 0) return '0'; if (diff < 0) return '0';
const hours = Math.floor(diff / 60); const hours = Math.floor(diff / 60);
@@ -186,7 +185,7 @@ const JobProcessStatus: React.FC = () => {
<CardContent> <CardContent>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}> <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
<Typography variant="h5" sx={{ fontWeight: 600 }}> <Typography variant="h5" sx={{ fontWeight: 600 }}>
{t("Job Process Status", { ns: "jobProcessStatus" })}
{t("Job Process Status", )}
</Typography> </Typography>
</Box> </Box>
@@ -203,30 +202,26 @@ const JobProcessStatus: React.FC = () => {
<TableRow> <TableRow>
<TableCell rowSpan={3}> <TableCell rowSpan={3}>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}> <Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
{t("Job Order No.", { ns: "jobProcessStatus" })}
{t("Job Order No.")}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell rowSpan={3}> <TableCell rowSpan={3}>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}> <Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
{t("FG / WIP Item", { ns: "jobProcessStatus" })}
{t("FG / WIP Item")}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell rowSpan={3}> <TableCell rowSpan={3}>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}> <Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
{t("Production Time Remaining", { ns: "jobProcessStatus" })}
</Typography>
</TableCell>
<TableCell colSpan={6} align="center">
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
{t("Process Status / Time [hh:mm]", { ns: "jobProcessStatus" })}
{t("Production Time Remaining")}
</Typography> </Typography>
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
{[1, 2, 3, 4, 5, 6].map((num) => ( {[1, 2, 3, 4, 5, 6].map((num) => (
<TableCell key={num} align="center"> <TableCell key={num} align="center">
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}> <Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
{t("Process", { ns: "jobProcessStatus" })} {num}
{t("Process")} {num}
</Typography> </Typography>
</TableCell> </TableCell>
))} ))}
@@ -236,13 +231,13 @@ const JobProcessStatus: React.FC = () => {
<TableCell key={num} align="center"> <TableCell key={num} align="center">
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}> <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
<Typography variant="caption" sx={{ fontWeight: 600 }}> <Typography variant="caption" sx={{ fontWeight: 600 }}>
{t("Start", { ns: "jobProcessStatus" })}
{t("Start")}
</Typography> </Typography>
<Typography variant="caption" sx={{ fontWeight: 600 }}> <Typography variant="caption" sx={{ fontWeight: 600 }}>
{t("Finish", { ns: "jobProcessStatus" })}
{t("Finish")}
</Typography> </Typography>
<Typography variant="caption" sx={{ fontWeight: 600 }}> <Typography variant="caption" sx={{ fontWeight: 600 }}>
{t("Wait Time [minutes]", { ns: "jobProcessStatus" })}
{t("Wait Time [minutes]")}
</Typography> </Typography>
</Box> </Box>
</TableCell> </TableCell>
@@ -268,7 +263,7 @@ const JobProcessStatus: React.FC = () => {
</TableCell> </TableCell>
<TableCell> <TableCell>


{calculateRemainingTime(row.planEndTime)}
{calculateRemainingTime(row.planEndTime, row.processingTime, row.setupTime, row.changeoverTime)}
</TableCell> </TableCell>
{row.processes.map((process, index) => { {row.processes.map((process, index) => {
const isLastProcess = index === row.processes.length - 1 || const isLastProcess = index === row.processes.length - 1 ||


+ 1
- 1
src/components/ProductionProcess/ProductionProcessList.tsx Просмотреть файл

@@ -142,7 +142,7 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ onSelectProcess
} }
// 3) 更新 JO 状态 // 3) 更新 JO 状态
await updateJo({ id: process.jobOrderId, status: "completed" });
// await updateJo({ id: process.jobOrderId, status: "completed" });
// 4) 刷新列表 // 4) 刷新列表
await fetchProcesses(); await fetchProcesses();


+ 19
- 17
src/components/StockIn/FgStockInForm.tsx Просмотреть файл

@@ -365,26 +365,28 @@ return (
</Grid></> </Grid></>
)} */} )} */}
<Grid item xs={6}> <Grid item xs={6}>
<Controller
control={control}
name="expiryDate"
// rules={{ required: !Boolean(productionDate) }}
render={({ field }) => {
return (
<LocalizationProvider
dateAdapter={AdapterDayjs}
adapterLocale={`${language}-hk`}
>
<Controller
control={control}
name="expiryDate"
render={({ field }) => {
const expiryDateValue = watch("expiryDate");
return (
<LocalizationProvider
dateAdapter={AdapterDayjs}
adapterLocale={`${language}-hk`}
>
<DatePicker <DatePicker
{...field} {...field}
sx={textfieldSx} sx={textfieldSx}
label={t("expiryDate")} label={t("expiryDate")}
value={expiryDate ? dayjs(expiryDate) : undefined}
value={expiryDateValue ? dayjs(expiryDateValue) : null} // Use null instead of undefined
format={OUTPUT_DATE_FORMAT} format={OUTPUT_DATE_FORMAT}
disabled={disabled} disabled={disabled}
onChange={(date) => { onChange={(date) => {
if (!date) return;
console.log(date.format(INPUT_DATE_FORMAT));
if (!date) {
setValue("expiryDate", "");
return;
}
setValue("expiryDate", date.format(INPUT_DATE_FORMAT)); setValue("expiryDate", date.format(INPUT_DATE_FORMAT));
}} }}
inputRef={field.ref} inputRef={field.ref}
@@ -416,10 +418,10 @@ return (
}, },
}} }}
/> />
</LocalizationProvider>
);
}}
/>
</LocalizationProvider>
);
}}
/>
</Grid> </Grid>
{/* <Grid item xs={6}> {/* <Grid item xs={6}>
{putawayMode ? ( {putawayMode ? (


+ 7
- 2
src/config/authConfig.ts Просмотреть файл

@@ -2,7 +2,7 @@
import { AuthOptions } from "next-auth"; import { AuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials"; import CredentialsProvider from "next-auth/providers/credentials";
import { LOGIN_API_PATH } from "./api"; import { LOGIN_API_PATH } from "./api";
import { Session } from "next-auth";
// Extend the built-in types // Extend the built-in types
declare module "next-auth" { declare module "next-auth" {
interface Session { interface Session {
@@ -98,5 +98,10 @@ export const authOptions: AuthOptions = {
}, },
}, },
}; };

export type SessionWithTokens = Session & {
accessToken: string | null;
refreshToken?: string;
abilities: string[];
id?: string;
};
export default authOptions; export default authOptions;

+ 6
- 1
src/i18n/zh/common.json Просмотреть файл

@@ -49,7 +49,12 @@
"Assignment failed: ": "分配失敗: ", "Assignment failed: ": "分配失敗: ",
"Unknown error": "未知錯誤", "Unknown error": "未知錯誤",
"Job Process Status": "工單流程狀態", "Job Process Status": "工單流程狀態",
"FG / WIP Item": "成品/半成品",
"Total Time": "總時間",
"Remaining Time": "剩餘時間",
"Wait Time": "等待時間",
"Wait Time [minutes]": "等待時間(分鐘)",
"End Time": "完成時間",
"WIP": "半成品", "WIP": "半成品",
"R&D": "研發", "R&D": "研發",
"STF": "樣品", "STF": "樣品",


+ 3
- 0
src/i18n/zh/jo.json Просмотреть файл

@@ -4,11 +4,14 @@
"Edit Job Order Detail": "工單詳情", "Edit Job Order Detail": "工單詳情",
"Details": "細節", "Details": "細節",
"Actions": "操作", "Actions": "操作",
"Process": "工序",
"Create Job Order": "建立工單", "Create Job Order": "建立工單",
"Code": "工單編號", "Code": "工單編號",
"Name": "成品/半成品名稱", "Name": "成品/半成品名稱",
"Picked Qty": "已提料數量", "Picked Qty": "已提料數量",
"Confirm All": "確認所有提料", "Confirm All": "確認所有提料",
"Wait Time [minutes]": "等待時間(分鐘)",
"Job Process Status": "工單流程狀態",
"Search Job Order/ Create Job Order":"搜尋工單/建立工單", "Search Job Order/ Create Job Order":"搜尋工單/建立工單",
"UoM": "銷售單位", "UoM": "銷售單位",
"Select Another Bag Lot":"選擇另一個包裝袋", "Select Another Bag Lot":"選擇另一個包裝袋",


Загрузка…
Отмена
Сохранить