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.
 
 

293 rivejä
8.2 KiB

  1. "use client";
  2. import { PickOrderResult } from "@/app/api/pickOrder";
  3. import { useCallback, useEffect, useMemo, useState } from "react";
  4. import { useTranslation } from "react-i18next";
  5. import SearchBox, { Criterion } from "../SearchBox";
  6. import {
  7. flatten,
  8. intersectionWith,
  9. isEmpty,
  10. sortBy,
  11. uniqBy,
  12. upperCase,
  13. upperFirst,
  14. } from "lodash";
  15. import {
  16. arrayToDayjs,
  17. } from "@/app/utils/formatUtil";
  18. import { Button, Grid, Stack, Tab, Tabs, TabsProps, Typography, Box } from "@mui/material";
  19. import PickOrders from "./FinishedGood";
  20. import ConsolidatedPickOrders from "./ConsolidatedPickOrders";
  21. import PickExecution from "./GoodPickExecution";
  22. import CreatePickOrderModal from "./CreatePickOrderModal";
  23. import NewCreateItem from "./newcreatitem";
  24. import AssignAndRelease from "./AssignAndRelease";
  25. import AssignTo from "./assignTo";
  26. import { fetchAllItemsInClient, ItemCombo } from "@/app/api/settings/item/actions";
  27. import { fetchPickOrderClient } from "@/app/api/pickOrder/actions";
  28. import Jobcreatitem from "./Jobcreatitem";
  29. interface Props {
  30. pickOrders: PickOrderResult[];
  31. }
  32. type SearchQuery = Partial<
  33. Omit<PickOrderResult, "id" | "consoCode" | "completeDate">
  34. >;
  35. type SearchParamNames = keyof SearchQuery;
  36. const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
  37. const { t } = useTranslation("pickOrder");
  38. const [isOpenCreateModal, setIsOpenCreateModal] = useState(false)
  39. const [items, setItems] = useState<ItemCombo[]>([])
  40. const [filteredPickOrders, setFilteredPickOrders] = useState(pickOrders);
  41. const [filterArgs, setFilterArgs] = useState<Record<string, any>>({});
  42. const [searchQuery, setSearchQuery] = useState<Record<string, any>>({});
  43. const [tabIndex, setTabIndex] = useState(0);
  44. const [totalCount, setTotalCount] = useState<number>();
  45. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  46. (_e, newValue) => {
  47. setTabIndex(newValue);
  48. },
  49. [],
  50. );
  51. const openCreateModal = useCallback(async () => {
  52. console.log("testing")
  53. const res = await fetchAllItemsInClient()
  54. console.log(res)
  55. setItems(res)
  56. setIsOpenCreateModal(true)
  57. }, [])
  58. const closeCreateModal = useCallback(() => {
  59. setIsOpenCreateModal(false)
  60. }, [])
  61. useEffect(() => {
  62. if (tabIndex === 3) {
  63. const loadItems = async () => {
  64. try {
  65. const itemsData = await fetchAllItemsInClient();
  66. console.log("PickOrderSearch loaded items:", itemsData.length);
  67. setItems(itemsData);
  68. } catch (error) {
  69. console.error("Error loading items in PickOrderSearch:", error);
  70. }
  71. };
  72. // 如果还没有数据,则加载
  73. if (items.length === 0) {
  74. loadItems();
  75. }
  76. }
  77. }, [tabIndex, items.length]);
  78. const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
  79. () => {
  80. const baseCriteria: Criterion<SearchParamNames>[] = [
  81. {
  82. label: tabIndex === 3 ? t("Item Code") : t("Code"),
  83. paramName: "code",
  84. type: "text"
  85. },
  86. {
  87. label: t("Type"),
  88. paramName: "type",
  89. type: "autocomplete",
  90. options: tabIndex === 3
  91. ?
  92. [
  93. { value: "Consumable", label: t("Consumable") },
  94. { value: "Material", label: t("Material") },
  95. { value: "Product", label: t("Product") }
  96. ]
  97. :
  98. sortBy(
  99. uniqBy(
  100. pickOrders.map((po) => ({
  101. value: po.type,
  102. label: t(upperCase(po.type)),
  103. })),
  104. "value",
  105. ),
  106. "label",
  107. ),
  108. },
  109. ];
  110. // Add Job Order search for Create Item tab (tabIndex === 3)
  111. if (tabIndex === 3) {
  112. baseCriteria.splice(1, 0, {
  113. label: t("Job Order"),
  114. paramName: "jobOrderCode" as any, // Type assertion for now
  115. type: "text",
  116. });
  117. baseCriteria.splice(2, 0, {
  118. label: t("Target Date"),
  119. paramName: "targetDate",
  120. type: "date",
  121. });
  122. } else {
  123. baseCriteria.splice(1, 0, {
  124. label: t("Target Date From"),
  125. label2: t("Target Date To"),
  126. paramName: "targetDate",
  127. type: "dateRange",
  128. });
  129. }
  130. // Add Items/Item Name criteria
  131. baseCriteria.push({
  132. label: tabIndex === 3 ? t("Item Name") : t("Items"),
  133. paramName: "items",
  134. type: tabIndex === 3 ? "text" : "autocomplete",
  135. options: tabIndex === 3
  136. ? []
  137. :
  138. uniqBy(
  139. flatten(
  140. sortBy(
  141. pickOrders.map((po) =>
  142. po.items
  143. ? po.items.map((item) => ({
  144. value: item.name,
  145. label: item.name,
  146. }))
  147. : [],
  148. ),
  149. "label",
  150. ),
  151. ),
  152. "value",
  153. ),
  154. });
  155. // Add Status criteria for non-Create Item tabs
  156. if (tabIndex !== 3) {
  157. baseCriteria.push({
  158. label: t("Status"),
  159. paramName: "status",
  160. type: "autocomplete",
  161. options: sortBy(
  162. uniqBy(
  163. pickOrders.map((po) => ({
  164. value: po.status,
  165. label: t(upperFirst(po.status)),
  166. })),
  167. "value",
  168. ),
  169. "label",
  170. ),
  171. });
  172. }
  173. return baseCriteria;
  174. },
  175. [pickOrders, t, tabIndex, items],
  176. );
  177. const fetchNewPagePickOrder = useCallback(
  178. async (
  179. pagingController: Record<string, number>,
  180. filterArgs: Record<string, number>,
  181. ) => {
  182. const params = {
  183. ...pagingController,
  184. ...filterArgs,
  185. };
  186. const res = await fetchPickOrderClient(params);
  187. if (res) {
  188. console.log(res);
  189. setFilteredPickOrders(res.records);
  190. setTotalCount(res.total);
  191. }
  192. },
  193. [],
  194. );
  195. const onReset = useCallback(() => {
  196. setFilteredPickOrders(pickOrders);
  197. }, [pickOrders]);
  198. useEffect(() => {
  199. if (!isOpenCreateModal) {
  200. setTabIndex(1)
  201. setTimeout(async () => {
  202. setTabIndex(0)
  203. }, 200)
  204. }
  205. }, [isOpenCreateModal])
  206. // 添加处理提料单创建成功的函数
  207. const handlePickOrderCreated = useCallback(() => {
  208. // 切换到 Assign & Release 标签页 (tabIndex = 1)
  209. setTabIndex(2);
  210. }, []);
  211. return (
  212. <Box sx={{
  213. height: '100vh', // Full viewport height
  214. overflow: 'auto' // Single scrollbar for the whole page
  215. }}>
  216. {/* Header section */}
  217. <Box sx={{
  218. p: 2,
  219. borderBottom: '1px solid #e0e0e0'
  220. }}>
  221. <Stack rowGap={2}>
  222. <Grid container>
  223. <Grid item xs={8}>
  224. <Typography variant="h4" marginInlineEnd={2}>
  225. {t("Pick Order")}
  226. </Typography>
  227. </Grid>
  228. {/*
  229. <Grid item xs={4} display="flex" justifyContent="end" alignItems="end">
  230. <Button onClick={openCreateModal}>
  231. {t("create")}
  232. </Button>
  233. {isOpenCreateModal &&
  234. <CreatePickOrderModal
  235. open={isOpenCreateModal}
  236. onClose={closeCreateModal}
  237. items={items}
  238. />
  239. }
  240. </Grid>
  241. */}
  242. </Grid>
  243. </Stack>
  244. </Box>
  245. {/* Tabs section */}
  246. <Box sx={{
  247. borderBottom: '1px solid #e0e0e0'
  248. }}>
  249. <Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable">
  250. <Tab label={t("Assign")} iconPosition="end" />
  251. <Tab label={t("Release")} iconPosition="end" />
  252. <Tab label={t("Pick Execution")} iconPosition="end" />
  253. </Tabs>
  254. </Box>
  255. {/* Content section - NO overflow: 'auto' here */}
  256. <Box sx={{
  257. p: 2
  258. }}>
  259. {tabIndex === 2 && <PickExecution filterArgs={filterArgs} />}
  260. {tabIndex === 0 && <AssignAndRelease filterArgs={filterArgs} />}
  261. {tabIndex === 1 && <AssignTo filterArgs={filterArgs} />}
  262. </Box>
  263. </Box>
  264. );
  265. };
  266. export default PickOrderSearch;