浏览代码

update

production_process
MSI\derek 2 个月前
父节点
当前提交
09638ea0a6
共有 9 个文件被更改,包括 370 次插入277 次删除
  1. +15
    -0
      src/app/api/po/actions.ts
  2. +15
    -4
      src/app/api/po/index.ts
  3. +5
    -0
      src/app/api/utils/index.ts
  4. +61
    -63
      src/components/ItemsSearch/ItemsSearch.tsx
  5. +2
    -2
      src/components/ItemsSearch/ItemsSearchWrapper.tsx
  6. +1
    -1
      src/components/PoDetail/PoDetail.tsx
  7. +30
    -6
      src/components/PoSearch/PoSearch.tsx
  8. +9
    -4
      src/components/PoSearch/PoSearchWrapper.tsx
  9. +232
    -197
      src/components/SearchResults/SearchResults.tsx

+ 15
- 0
src/app/api/po/actions.ts 查看文件

@@ -6,6 +6,7 @@ import { cache } from "react";
import { PoResult, StockInLine } from "."; import { PoResult, StockInLine } from ".";
import { serverFetchJson } from "@/app/utils/fetchUtil"; import { serverFetchJson } from "@/app/utils/fetchUtil";
import { QcItemResult } from "../settings/qcItem"; import { QcItemResult } from "../settings/qcItem";
import { RecordsRes } from "../utils";
// import { BASE_API_URL } from "@/config/api"; // import { BASE_API_URL } from "@/config/api";


export interface PostStockInLiineResponse<T> { export interface PostStockInLiineResponse<T> {
@@ -124,4 +125,18 @@ export const fetchPoInClient = cache(async (id: number) => {
}); });
}); });


export const fetchPoListClient = cache(async (queryParams?: Record<string, any>) => {
if (queryParams) {
const queryString = new URLSearchParams(queryParams).toString();
return serverFetchJson<RecordsRes<PoResult[]>>(`${BASE_API_URL}/po/list?${queryString}`, {
method: 'GET',
next: { tags: ["po"] },
});
} else {
return serverFetchJson<RecordsRes<PoResult[]>>(`${BASE_API_URL}/po/list`, {
method: 'GET',
next: { tags: ["po"] },
});
}
});



+ 15
- 4
src/app/api/po/index.ts 查看文件

@@ -3,6 +3,7 @@ import "server-only";
import { serverFetchJson } from "@/app/utils/fetchUtil"; import { serverFetchJson } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api"; import { BASE_API_URL } from "@/config/api";
import { Uom } from "../settings/uom"; import { Uom } from "../settings/uom";
import { RecordsRes } from "../utils";


export interface PoResult { export interface PoResult {
id: number id: number
@@ -55,10 +56,20 @@ export interface StockInLine {
defaultWarehouseId: number // id for now defaultWarehouseId: number // id for now
} }


export const fetchPoList = cache(async () => {
return serverFetchJson<PoResult[]>(`${BASE_API_URL}/po/list`, {
next: { tags: ["po"] },
});

export const fetchPoList = cache(async (queryParams?: Record<string, any>) => {
if (queryParams) {
const queryString = new URLSearchParams(queryParams).toString();
return serverFetchJson<RecordsRes<PoResult[]>>(`${BASE_API_URL}/po/list?${queryString}`, {
method: 'GET',
next: { tags: ["po"] },
});
} else {
return serverFetchJson<RecordsRes<PoResult[]>>(`${BASE_API_URL}/po/list`, {
method: 'GET',
next: { tags: ["po"] },
});
}
}); });


export const fetchPoWithStockInLines = cache(async (id: number) => { export const fetchPoWithStockInLines = cache(async (id: number) => {


+ 5
- 0
src/app/api/utils/index.ts 查看文件

@@ -4,4 +4,9 @@ export interface CreateItemResponse<T> {
code: string; code: string;
message: string | null; message: string | null;
errorPosition: string | keyof T; errorPosition: string | keyof T;
}

export interface RecordsRes<T>{
records: T
total: number
} }

+ 61
- 63
src/components/ItemsSearch/ItemsSearch.tsx 查看文件

@@ -1,8 +1,8 @@
"use client"; "use client";


import {useCallback, useEffect, useMemo, useState} from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import SearchBox, { Criterion } from "../SearchBox"; import SearchBox, { Criterion } from "../SearchBox";
import { ItemsResult} from "@/app/api/settings/item";
import { ItemsResult } from "@/app/api/settings/item";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults"; import SearchResults, { Column } from "../SearchResults";
import { EditNote } from "@mui/icons-material"; import { EditNote } from "@mui/icons-material";
@@ -10,7 +10,7 @@ import { useRouter, useSearchParams } from "next/navigation";
import { GridDeleteIcon } from "@mui/x-data-grid"; import { GridDeleteIcon } from "@mui/x-data-grid";
import { TypeEnum } from "@/app/utils/typeEnum"; import { TypeEnum } from "@/app/utils/typeEnum";
import axios from "axios"; import axios from "axios";
import {BASE_API_URL, NEXT_PUBLIC_API_URL} from "@/config/api";
import { BASE_API_URL, NEXT_PUBLIC_API_URL } from "@/config/api";
import axiosInstance from "@/app/(main)/axios/axiosInstance"; import axiosInstance from "@/app/(main)/axios/axiosInstance";


type Props = { type Props = {
@@ -25,21 +25,18 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
const router = useRouter(); const router = useRouter();
const [filterObj, setFilterObj] = useState({}); const [filterObj, setFilterObj] = useState({});
const [pagingController, setPagingController] = useState({ const [pagingController, setPagingController] = useState({
pageNum: 1,
pageSize: 10,
totalCount: 0,
})

const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => {
var searchCriteria: Criterion<SearchParamNames>[] = [
{ label: t("Code"), paramName: "code", type: "text" },
{ label: t("Name"), paramName: "name", type: "text" },
]
return searchCriteria
},
[t, items]
);
pageNum: 1,
pageSize: 10,
totalCount: 0,
});
const [totalCount, setTotalCount] = useState(0)
const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => {
var searchCriteria: Criterion<SearchParamNames>[] = [
{ label: t("Code"), paramName: "code", type: "text" },
{ label: t("Name"), paramName: "name", type: "text" },
];
return searchCriteria;
}, [t, items]);


const onDetailClick = useCallback( const onDetailClick = useCallback(
(item: ItemsResult) => { (item: ItemsResult) => {
@@ -48,10 +45,7 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
[router] [router]
); );


const onDeleteClick = useCallback(
(item: ItemsResult) => {},
[router]
);
const onDeleteClick = useCallback((item: ItemsResult) => {}, [router]);


const columns = useMemo<Column<ItemsResult>[]>( const columns = useMemo<Column<ItemsResult>[]>(
() => [ () => [
@@ -79,41 +73,45 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
[filteredItems] [filteredItems]
); );


useEffect(() => {
refetchData(filterObj);

}, [filterObj, pagingController.pageNum, pagingController.pageSize]);

const refetchData = async (filterObj: SearchQuery) => {

const authHeader = axiosInstance.defaults.headers['Authorization'];
if (!authHeader) {
return; // Exit the function if the token is not set
}

const params ={
pageNum: pagingController.pageNum,
pageSize: pagingController.pageSize,
...filterObj,
const refetchData = useCallback(
async (filterObj: SearchQuery) => {
const authHeader = axiosInstance.defaults.headers["Authorization"];
if (!authHeader) {
return; // Exit the function if the token is not set
}
const params = {
pageNum: pagingController.pageNum,
pageSize: pagingController.pageSize,
...filterObj,
};
try {
const response = await axiosInstance.get<ItemsResult[]>(
`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`,
{ params }
);
console.log(response);
if (response.status == 200) {
setFilteredItems(response.data.records);
setTotalCount(response.data.total)
return response; // Return the data from the response
} else {
throw "400";
} }
} catch (error) {
console.error("Error fetching items:", error);
throw error; // Rethrow the error for further handling
}
},
[axiosInstance, pagingController.pageNum, pagingController.pageSize]
);


try {
const response = await axiosInstance.get<ItemsResult[]>(`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, { params });
setFilteredItems(response.data.records);
setPagingController({
...pagingController,
totalCount: response.data.total
})
return response; // Return the data from the response
} catch (error) {
console.error('Error fetching items:', error);
throw error; // Rethrow the error for further handling
}
};
useEffect(() => {
refetchData(filterObj);
}, [filterObj, pagingController.pageNum, pagingController.pageSize]);


const onReset = useCallback(() => {
setFilteredItems(items);
}, [items]);
const onReset = useCallback(() => {
setFilteredItems(items);
}, [items]);


return ( return (
<> <>
@@ -128,19 +126,19 @@ const ItemsSearch: React.FC<Props> = ({ items }) => {
// ); // );
// }) // })
// ); // );
// @ts-ignore
setFilterObj({
...query
})
setFilterObj({
...query,
});
}} }}
onReset={onReset} onReset={onReset}
/> />
<SearchResults<ItemsResult> <SearchResults<ItemsResult>
items={filteredItems}
columns={columns}
setPagingController={setPagingController}
pagingController={pagingController}
isAutoPaging={false}
items={filteredItems}
columns={columns}
setPagingController={setPagingController}
pagingController={pagingController}
totalCount={totalCount}
isAutoPaging={false}
/> />
</> </>
); );


+ 2
- 2
src/components/ItemsSearch/ItemsSearchWrapper.tsx 查看文件

@@ -17,8 +17,8 @@ const ItemsSearchWrapper: React.FC<Props> & SubComponents = async ({
// type, // type,
}) => { }) => {
// console.log(type) // console.log(type)
var result = await fetchAllItems()
return <ItemsSearch items={result} />;
// var result = await fetchAllItems()
return <ItemsSearch items={[]} />;
}; };


ItemsSearchWrapper.Loading = ItemsSearchLoading; ItemsSearchWrapper.Loading = ItemsSearchLoading;


+ 1
- 1
src/components/PoDetail/PoDetail.tsx 查看文件

@@ -344,7 +344,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
{/* tab 1 */} {/* tab 1 */}
<Grid sx={{ display: tabIndex === 0 ? "block" : "none" }}> <Grid sx={{ display: tabIndex === 0 ? "block" : "none" }}>
<TableContainer component={Paper}> <TableContainer component={Paper}>
<Table aria-label="collapsible table">
<Table aria-label="collapsible table" stickyHeader>
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell /> {/* for the collapse button */} <TableCell /> {/* for the collapse button */}


+ 30
- 6
src/components/PoSearch/PoSearch.tsx 查看文件

@@ -1,7 +1,7 @@
"use client"; "use client";


import { PoResult } from "@/app/api/po"; import { PoResult } from "@/app/api/po";
import { useCallback, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import SearchBox, { Criterion } from "../SearchBox"; import SearchBox, { Criterion } from "../SearchBox";
@@ -12,19 +12,25 @@ import QrModal from "../PoDetail/QrModal";
import { WarehouseResult } from "@/app/api/warehouse"; import { WarehouseResult } from "@/app/api/warehouse";
import NotificationIcon from '@mui/icons-material/NotificationImportant'; import NotificationIcon from '@mui/icons-material/NotificationImportant';
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import { defaultPagingController } from "../SearchResults/SearchResults";
import { fetchPoListClient } from "@/app/api/po/actions";


type Props = { type Props = {
po: PoResult[]; po: PoResult[];
warehouse: WarehouseResult[]; warehouse: WarehouseResult[];
totalCount: number;
}; };
type SearchQuery = Partial<Omit<PoResult, "id">>; type SearchQuery = Partial<Omit<PoResult, "id">>;
type SearchParamNames = keyof SearchQuery; type SearchParamNames = keyof SearchQuery;


const PoSearch: React.FC<Props> = ({ po, warehouse }) => {
// cal offset (pageSize)
// cal limit (pageSize)
const PoSearch: React.FC<Props> = ({ po, warehouse, totalCount: initTotalCount }) => {
const [filteredPo, setFilteredPo] = useState<PoResult[]>(po); const [filteredPo, setFilteredPo] = useState<PoResult[]>(po);
const { t } = useTranslation("purchaseOrder"); const { t } = useTranslation("purchaseOrder");
const router = useRouter(); const router = useRouter();

const [pagingController, setPagingController] = useState(defaultPagingController)
const [totalCount, setTotalCount] = useState(initTotalCount)
const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => { const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => {
var searchCriteria: Criterion<SearchParamNames>[] = [ var searchCriteria: Criterion<SearchParamNames>[] = [
{ label: t("Code"), paramName: "code", type: "text" }, { label: t("Code"), paramName: "code", type: "text" },
@@ -102,6 +108,17 @@ const PoSearch: React.FC<Props> = ({ po, warehouse }) => {
setOpenScanner(false); setOpenScanner(false);
}, []); }, []);


const newPageFetch = useCallback(async (pagingController: Record<string, number>) => {
const res = await fetchPoListClient(pagingController)
if (res) {
setFilteredPo(res.records)
setTotalCount(res.total)
}
}, [fetchPoListClient, pagingController])

useEffect(() => {
newPageFetch(pagingController)
}, [newPageFetch, pagingController])
return ( return (
<> <>
<Grid container> <Grid container>
@@ -129,8 +146,8 @@ const PoSearch: React.FC<Props> = ({ po, warehouse }) => {
<SearchBox <SearchBox
criteria={searchCriteria} criteria={searchCriteria}
onSearch={(query) => { onSearch={(query) => {
setFilteredPo(
po.filter((p) => {
setFilteredPo((prev) =>
prev.filter((p) => {
return ( return (
p.code.toLowerCase().includes(query.code.toLowerCase()) && p.code.toLowerCase().includes(query.code.toLowerCase()) &&
(query.status === "All" || p.status === query.status) && (query.status === "All" || p.status === query.status) &&
@@ -141,7 +158,14 @@ const PoSearch: React.FC<Props> = ({ po, warehouse }) => {
}} }}
onReset={onReset} onReset={onReset}
/> />
<SearchResults<PoResult> items={filteredPo} columns={columns} />
<SearchResults<PoResult>
items={filteredPo}
columns={columns}
pagingController={pagingController}
setPagingController={setPagingController}
totalCount={totalCount}
isAutoPaging={false}
/>
</> </>


</> </>


+ 9
- 4
src/components/PoSearch/PoSearchWrapper.tsx 查看文件

@@ -11,6 +11,7 @@ import dayjs from "dayjs";
import arraySupport from "dayjs/plugin/arraySupport"; import arraySupport from "dayjs/plugin/arraySupport";
import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import { fetchWarehouseList } from "@/app/api/warehouse"; import { fetchWarehouseList } from "@/app/api/warehouse";
import { defaultPagingController } from "../SearchResults/SearchResults";
dayjs.extend(arraySupport); dayjs.extend(arraySupport);


interface SubComponents { interface SubComponents {
@@ -26,21 +27,25 @@ const PoSearchWrapper: React.FC<Props> & SubComponents = async (
// type, // type,
} }
) => { ) => {
// console.log(defaultPagingController)
const [ const [
po, po,
warehouse, warehouse,
] = await Promise.all([ ] = await Promise.all([
fetchPoList(),
fetchPoList({
"pageNum": 1,
"pageSize": 10,
}),
fetchWarehouseList(), fetchWarehouseList(),
]); ]);
console.log(po)
const fixPoDate = po.map((p) => {
console.log(po.records.length)
const fixPoDate = po.records.map((p) => {
return ({ return ({
...p, ...p,
orderDate: dayjs(p.orderDate).add(-1, "month").format(OUTPUT_DATE_FORMAT) orderDate: dayjs(p.orderDate).add(-1, "month").format(OUTPUT_DATE_FORMAT)
}) })
}) })
return <PoSearch po={fixPoDate} warehouse={warehouse}/>;
return <PoSearch po={fixPoDate} warehouse={warehouse} totalCount={po.total}/>;
}; };


PoSearchWrapper.Loading = PoSearchLoading; PoSearchWrapper.Loading = PoSearchLoading;


+ 232
- 197
src/components/SearchResults/SearchResults.tsx 查看文件

@@ -1,6 +1,6 @@
"use client"; "use client";


import React from "react";
import React, { Dispatch, SetStateAction } from "react";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import Table from "@mui/material/Table"; import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody"; import TableBody from "@mui/material/TableBody";
@@ -8,279 +8,314 @@ import TableCell, { TableCellProps } from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer"; import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead"; import TableHead from "@mui/material/TableHead";
import TablePagination, { import TablePagination, {
TablePaginationProps,
TablePaginationProps,
} from "@mui/material/TablePagination"; } from "@mui/material/TablePagination";
import TableRow from "@mui/material/TableRow"; import TableRow from "@mui/material/TableRow";
import IconButton, { IconButtonOwnProps } from "@mui/material/IconButton"; import IconButton, { IconButtonOwnProps } from "@mui/material/IconButton";
import { ButtonOwnProps, Icon, IconOwnProps, SxProps, Theme } from "@mui/material";
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
import {
ButtonOwnProps,
Icon,
IconOwnProps,
SxProps,
Theme,
} from "@mui/material";
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";


export interface ResultWithId { export interface ResultWithId {
id: string | number;
id: string | number;
} }


type ColumnType = "icon" | "decimal" | "integer"; type ColumnType = "icon" | "decimal" | "integer";


interface BaseColumn<T extends ResultWithId> { interface BaseColumn<T extends ResultWithId> {
name: keyof T;
label: string;
align?: TableCellProps["align"];
headerAlign?: TableCellProps["align"];
sx?: SxProps<Theme> | undefined;
style?: Partial<HTMLElement["style"]> & { [propName: string]: string };
type?: ColumnType;
renderCell?: (params: T) => React.ReactNode;
name: keyof T;
label: string;
align?: TableCellProps["align"];
headerAlign?: TableCellProps["align"];
sx?: SxProps<Theme> | undefined;
style?: Partial<HTMLElement["style"]> & { [propName: string]: string };
type?: ColumnType;
renderCell?: (params: T) => React.ReactNode;
} }


interface IconColumn<T extends ResultWithId> extends BaseColumn<T> { interface IconColumn<T extends ResultWithId> extends BaseColumn<T> {
name: keyof T;
type: "icon";
icon?: React.ReactNode;
icons?: { [columnValue in keyof T]: React.ReactNode };
color?: IconOwnProps["color"];
colors?: { [columnValue in keyof T]: IconOwnProps["color"] };
name: keyof T;
type: "icon";
icon?: React.ReactNode;
icons?: { [columnValue in keyof T]: React.ReactNode };
color?: IconOwnProps["color"];
colors?: { [columnValue in keyof T]: IconOwnProps["color"] };
} }


interface DecimalColumn<T extends ResultWithId> extends BaseColumn<T> { interface DecimalColumn<T extends ResultWithId> extends BaseColumn<T> {
type: "decimal";
type: "decimal";
} }


interface IntegerColumn<T extends ResultWithId> extends BaseColumn<T> { interface IntegerColumn<T extends ResultWithId> extends BaseColumn<T> {
type: "integer";
type: "integer";
} }


interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> { interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> {
onClick: (item: T) => void;
buttonIcon: React.ReactNode;
buttonIcons: { [columnValue in keyof T]: React.ReactNode };
buttonColor?: IconButtonOwnProps["color"];
onClick: (item: T) => void;
buttonIcon: React.ReactNode;
buttonIcons: { [columnValue in keyof T]: React.ReactNode };
buttonColor?: IconButtonOwnProps["color"];
} }


export type Column<T extends ResultWithId> = export type Column<T extends ResultWithId> =
| BaseColumn<T>
| IconColumn<T>
| DecimalColumn<T>
| ColumnWithAction<T>;
| BaseColumn<T>
| IconColumn<T>
| DecimalColumn<T>
| ColumnWithAction<T>;


interface Props<T extends ResultWithId> { interface Props<T extends ResultWithId> {
items: T[],
columns: Column<T>[],
noWrapper?: boolean,
setPagingController?: (value: (((prevState: { pageNum: number; pageSize: number; totalCount: number }) => {
pageNum: number;
pageSize: number;
totalCount: number
}) | { pageNum: number; pageSize: number; totalCount: number })) => void,
pagingController: { pageNum: number; pageSize: number; totalCount: number },
isAutoPaging?: boolean
totalCount?: number;
items: T[];
columns: Column<T>[];
noWrapper?: boolean;
setPagingController?: Dispatch<SetStateAction<{
pageNum: number;
pageSize: number;
}>>
pagingController: { pageNum: number; pageSize: number;};
isAutoPaging?: boolean;
} }


function isActionColumn<T extends ResultWithId>( function isActionColumn<T extends ResultWithId>(
column: Column<T>,
column: Column<T>
): column is ColumnWithAction<T> { ): column is ColumnWithAction<T> {
return Boolean((column as ColumnWithAction<T>).onClick);
return Boolean((column as ColumnWithAction<T>).onClick);
} }


function isIconColumn<T extends ResultWithId>( function isIconColumn<T extends ResultWithId>(
column: Column<T>,
column: Column<T>
): column is IconColumn<T> { ): column is IconColumn<T> {
return column.type === "icon";
return column.type === "icon";
} }


function isDecimalColumn<T extends ResultWithId>( function isDecimalColumn<T extends ResultWithId>(
column: Column<T>,
column: Column<T>
): column is DecimalColumn<T> { ): column is DecimalColumn<T> {
return column.type === "decimal";
return column.type === "decimal";
} }


function isIntegerColumn<T extends ResultWithId>( function isIntegerColumn<T extends ResultWithId>(
column: Column<T>,
column: Column<T>
): column is IntegerColumn<T> { ): column is IntegerColumn<T> {
return column.type === "integer";
return column.type === "integer";
} }


// Icon Component Functions // Icon Component Functions
function convertObjectKeysToLowercase<T extends object>(obj: T): object | undefined {
return obj ? Object.fromEntries(
function convertObjectKeysToLowercase<T extends object>(
obj: T
): object | undefined {
return obj
? Object.fromEntries(
Object.entries(obj).map(([key, value]) => [key.toLowerCase(), value]) Object.entries(obj).map(([key, value]) => [key.toLowerCase(), value])
) : undefined;
)
: undefined;
} }


function handleIconColors<T extends ResultWithId>( function handleIconColors<T extends ResultWithId>(
column: IconColumn<T>,
value: T[keyof T],
column: IconColumn<T>,
value: T[keyof T]
): IconOwnProps["color"] { ): IconOwnProps["color"] {
const colors = convertObjectKeysToLowercase(column.colors ?? {});
const valueKey = String(value).toLowerCase() as keyof typeof colors;
const colors = convertObjectKeysToLowercase(column.colors ?? {});
const valueKey = String(value).toLowerCase() as keyof typeof colors;


if (colors && valueKey in colors) {
return colors[valueKey];
}
if (colors && valueKey in colors) {
return colors[valueKey];
}


return column.color ?? "primary";
};
return column.color ?? "primary";
}


function handleIconIcons<T extends ResultWithId>( function handleIconIcons<T extends ResultWithId>(
column: IconColumn<T>,
value: T[keyof T],
column: IconColumn<T>,
value: T[keyof T]
): React.ReactNode { ): React.ReactNode {
const icons = convertObjectKeysToLowercase(column.icons ?? {});
const valueKey = String(value).toLowerCase() as keyof typeof icons;
const icons = convertObjectKeysToLowercase(column.icons ?? {});
const valueKey = String(value).toLowerCase() as keyof typeof icons;


if (icons && valueKey in icons) {
return icons[valueKey];
}

return column.icon ?? <CheckCircleOutlineIcon fontSize="small" />;
};
if (icons && valueKey in icons) {
return icons[valueKey];
}


return column.icon ?? <CheckCircleOutlineIcon fontSize="small" />;
}
export const defaultPagingController:{ pageNum: number; pageSize: number} = {
"pageNum": 1,
"pageSize": 10,
}
function SearchResults<T extends ResultWithId>({ function SearchResults<T extends ResultWithId>({
items,
columns,
noWrapper,
pagingController,
setPagingController,
isAutoPaging = true,
items,
columns,
noWrapper,
pagingController,
setPagingController,
isAutoPaging = true,
totalCount
}: Props<T>) { }: Props<T>) {
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(10);
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(10);


/// this
const handleChangePage: TablePaginationProps["onPageChange"] = (
_event,
newPage,
) => {
console.log(_event)
setPage(newPage);
if (setPagingController) {
setPagingController({
...pagingController,
pageNum: newPage + 1,
})
}
/// this
const handleChangePage: TablePaginationProps["onPageChange"] = (
_event,
newPage
) => {
console.log(_event);
setPage(newPage);
if (setPagingController) {
setPagingController({
...pagingController,
pageNum: newPage + 1,
});
} }
};


const handleChangeRowsPerPage: TablePaginationProps["onRowsPerPageChange"] = (
event,
) => {
console.log(event)
setRowsPerPage(+event.target.value);
setPage(0);
if (setPagingController) {
setPagingController({
...pagingController,
pageNum: +event.target.value,
})
}
};
const handleChangeRowsPerPage: TablePaginationProps["onRowsPerPageChange"] = (
event
) => {
console.log(event);
setRowsPerPage(+event.target.value);
setPage(0);
if (setPagingController) {
setPagingController({
...pagingController,
pageNum: +event.target.value,
});
}
};


const table = (
<>
<TableContainer sx={{ maxHeight: 440 }}>
<Table stickyHeader>
<TableHead>
<TableRow>
{columns.map((column, idx) => (
<TableCell align={column.headerAlign} sx={column.sx} key={`${column.name.toString()}${idx}`}>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{
isAutoPaging ?
items
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((item) => {
return (
<TableRow hover tabIndex={-1} key={item.id}>
{columns.map((column, idx) => {
const columnName = column.name;
const table = (
<>
<TableContainer sx={{ maxHeight: 440 }}>
<Table stickyHeader>
<TableHead>
<TableRow>
{columns.map((column, idx) => (
<TableCell
align={column.headerAlign}
sx={column.sx}
key={`${column.name.toString()}${idx}`}
>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{isAutoPaging
? items
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((item) => {
return (
<TableRow hover tabIndex={-1} key={item.id}>
{columns.map((column, idx) => {
const columnName = column.name;


return (
<TabelCells key={`${columnName.toString()}-${idx}`} column={column} columnName={columnName} idx={idx} item={item}/>
);
})}
</TableRow>
);
})
:
items
.map((item) => {
return (
<TableRow hover tabIndex={-1} key={item.id}>
{columns.map((column, idx) => {
const columnName = column.name;
return (
<TabelCells
key={`${columnName.toString()}-${idx}`}
column={column}
columnName={columnName}
idx={idx}
item={item}
/>
);
})}
</TableRow>
);
})
: items.map((item) => {
return (
<TableRow hover tabIndex={-1} key={item.id}>
{columns.map((column, idx) => {
const columnName = column.name;


return (
<TabelCells key={`${columnName.toString()}-${idx}`} column={column} columnName={columnName} idx={idx} item={item}/>
return (
<TabelCells
key={`${columnName.toString()}-${idx}`}
column={column}
columnName={columnName}
idx={idx}
item={item}
/>
); );
})}
</TableRow>
);
})
}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[10, 25, 100]}
component="div"
count={!pagingController || pagingController.totalCount == 0 ? items.length : pagingController.totalCount}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</>
);
})}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[10, 25, 100]}
component="div"
count={!totalCount || totalCount == 0
? items.length
: totalCount
}
// count={
// !pagingController || pagingController.totalCount == 0
// ? items.length
// : pagingController.totalCount
// }
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</>
);


return noWrapper ? table : <Paper sx={{ overflow: "hidden" }}>{table}</Paper>;
return noWrapper ? table : <Paper sx={{ overflow: "hidden" }}>{table}</Paper>;
} }


// Table cells // Table cells
interface TableCellsProps<T extends ResultWithId> { interface TableCellsProps<T extends ResultWithId> {
column: Column<T>,
columnName: keyof T,
idx: number,
item: T,
column: Column<T>;
columnName: keyof T;
idx: number;
item: T;
} }


function TabelCells<T extends ResultWithId>({ function TabelCells<T extends ResultWithId>({
column,
columnName,
idx,
item
column,
columnName,
idx,
item,
}: TableCellsProps<T>) { }: TableCellsProps<T>) {
return (
<TableCell align={column.align} sx={column.sx} key={`${columnName.toString()}-${idx}`}>
{isActionColumn(column) ? (
<IconButton
color={column.buttonColor ?? "primary"}
onClick={() => column.onClick(item)}
>
{column.buttonIcon}
</IconButton>
) :
isIconColumn(column) ? (
<Icon
color={handleIconColors(column, item[columnName])}
>
{handleIconIcons(column, item[columnName])}
</Icon>
) :
isDecimalColumn(column) ? (
<>{decimalFormatter.format(Number(item[columnName]))}</>
) :
isIntegerColumn(column) ? (
<>{integerFormatter.format(Number(item[columnName]))}</>
) :
(
column.renderCell ? column.renderCell(item) : <>{item[columnName] as string}</>
)}
</TableCell>)
return (
<TableCell
align={column.align}
sx={column.sx}
key={`${columnName.toString()}-${idx}`}
>
{isActionColumn(column) ? (
<IconButton
color={column.buttonColor ?? "primary"}
onClick={() => column.onClick(item)}
>
{column.buttonIcon}
</IconButton>
) : isIconColumn(column) ? (
<Icon color={handleIconColors(column, item[columnName])}>
{handleIconIcons(column, item[columnName])}
</Icon>
) : isDecimalColumn(column) ? (
<>{decimalFormatter.format(Number(item[columnName]))}</>
) : isIntegerColumn(column) ? (
<>{integerFormatter.format(Number(item[columnName]))}</>
) : column.renderCell ? (
column.renderCell(item)
) : (
<>{item[columnName] as string}</>
)}
</TableCell>
);
} }


export default SearchResults; export default SearchResults;

正在加载...
取消
保存