import React, { useEffect, useReducer, useCallback, useRef } from "react"; import { createPortal } from "react-dom"; import { useOutletContext } from "react-router"; import { TreeSelector, type TreeItemWithUnknown, } from "../../components/TreeSelector"; import { LoadMore } from "../../components/LoadMore"; import { orderByTypes } from "../../store/Types"; import { productReducer, initialState } from "../../store/product"; import * as actions from "../../store/product/action"; import { getCategoryTree, productList, productDetail, productDelete, productEdit, upload, } from "../../api"; import { type Category, ProductOrderBys, type ProductOrderBysType, UploadScences, } from "../../api/models"; import styles from "./index.module.css"; export function Component() { const [states, dispatch] = useReducer(productReducer, initialState); const asideContainer = useOutletContext(); const keywordRef = useRef(null); useEffect(() => { async function getTree() { try { const resp = await getCategoryTree(); if (resp.isSucced) { dispatch(actions.setCategories(resp.data || [])); } else { throw Error(resp.message || ""); } } finally { dispatch(actions.setLoading(false)); } } getTree(); }, []); function categoryChecked(item: TreeItemWithUnknown) { const category = item as Category; dispatch(actions.setCategory(category)); } const search = useCallback(async () => { try { dispatch(actions.setIsSearch(true)); const orderBys: ProductOrderBysType[] = []; if ( !states.orderBys.createTime || states.orderBys.createTime == orderByTypes.ASC ) orderBys.push(ProductOrderBys.CreateTimeDesc); if ( !states.orderBys.categoryId || states.orderBys.categoryId == orderByTypes.ASC ) orderBys.push(ProductOrderBys.Category); else orderBys.push(ProductOrderBys.CategoryDesc); if ( !states.orderBys.createTime || states.orderBys.createTime == orderByTypes.ASC ) orderBys.push(ProductOrderBys.CreateTime); else orderBys.push(ProductOrderBys.CreateTimeDesc); const result = await productList({ categoryId: states.categoryId, keyword: states.keyword, orderBys: orderBys, pageIndex: states.pageIndex, pageSize: states.pageSize, }); if (result.isSucced) { dispatch( actions.setSearchResult({ pageCount: result.data?.pageCount || 0, products: result.data?.data || [], }), ); } else { alert(result.message || "服务器错误"); } } finally { dispatch(actions.setIsSearch(false)); } }, [ states.categoryId, states.keyword, states.orderBys, states.pageIndex, states.pageSize, ]); useEffect(() => { search(); }, [search]); async function onLoadMore() { dispatch(actions.setPageIndex(states.pageIndex + 1)); } async function viewDetailClick(id: number) { try { const detailResult = await productDetail(id); if (detailResult.isSucced) { dispatch(actions.setEditProduct({ ...detailResult.data })); } else { throw Error(detailResult.message || "服务器错误"); } } catch (err) { throw Error(err as string); } } async function pictureSelected(e: React.ChangeEvent) { const el = e.target as HTMLInputElement; if (el.files && el.files.length) { try { const uploadResult = await upload({ file: el.files[0], scences: UploadScences.Product, }); if (uploadResult.isSucced) { dispatch( actions.setEditProduct({ logoName: uploadResult.data?.newName, logoUrl: uploadResult.data?.url, }), ); } else { throw Error(uploadResult.message || "服务器错误"); } } catch (err) { throw Error(err as string); } } } const saveDetail = useCallback(async () => { if (!states.editProduct.categoryId) { alert("请选择分类"); return; } if (!states.editProduct.name) { alert("请输入名称"); return; } if (!states.editProduct.minimumUnit) { alert("请输入单位"); return; } if (!states.editProduct.unitPrice) { alert("请输入单价"); return; } try { const editResult = await productEdit({ categoryId: states.editProduct.categoryId || 0, description: states.editProduct.description || "", detail: states.editProduct.detail || "", id: states.editProduct.id || 0, logoName: states.editProduct.logoName || "", minimumUnit: states.editProduct.minimumUnit || "", name: states.editProduct.name || "", unitPrice: states.editProduct.unitPrice || 0, }); if (editResult.isSucced) { alert("保存成功"); } else { throw Error(editResult.message || "服务器错误"); } } catch (err) { throw Error(err as string); } }, [states.editProduct]); async function deleteProduct(productId: number) { try { const deleteResult = await productDelete(productId); if (deleteResult.isSucced) { dispatch(actions.removeProduct(productId)); } else { throw Error(deleteResult.message || "服务器错误"); } } catch (err) { throw Error(err as string); } } function searchClick() { if (keywordRef.current) { dispatch(actions.setKeyword(keywordRef.current.value)); } } return ( <>
{!states.isLoading && ( )}
dispatch(actions.setKeyword(e.target.value))} onKeyDown={(e) => { if (e.key == "Enter") searchClick(); }} />
{states.products.map((prod) => { return (
viewDetailClick(prod.id)} >

{prod.name}

{prod.categoryName}

{prod.unitPrice}元/ {prod.minimumUnit}

已售:{prod.soldAmount}

{prod.createTime}

{prod.description}

); })}
{asideContainer && createPortal(
dispatch(actions.setEditProduct({ name: e.target.value })) } />
, asideContainer, )} ); }