Product.jsx 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { useEffect, useMemo } from 'react';
  2. import { Fragment } from 'react'
  3. import { getAllProducts } from '../api/product';
  4. import { useDispatch, useSelector } from 'react-redux';
  5. import { fetchProduct, setShowStock, setFilterName } from '../store/slice/productSlice';
  6. function Product() {
  7. const dispatch = useDispatch();
  8. useEffect(() => {
  9. dispatch(fetchProduct())
  10. }, [dispatch])
  11. const { products, filterName, showStock } = useSelector(x => x.productSlice);
  12. const filterProducts = useMemo(() => {
  13. return products.filter(item => item.name.includes(filterName) && (showStock ? item.stocked : true))
  14. }, [products, filterName, showStock])
  15. const renderProduct = () => {
  16. let prevCategory = ''
  17. return filterProducts.map((product, index) => {
  18. const showCategoryHeader = prevCategory !== product.category
  19. prevCategory = product.category
  20. return (
  21. <Fragment key={product.name + index}>
  22. {showCategoryHeader && (
  23. <tr style={{ background: '#e8f0fe' }}>
  24. <td colSpan={2}>
  25. <strong>{product.category}</strong>
  26. </td>
  27. </tr>
  28. )}
  29. <tr>
  30. <td>
  31. <span style={{ color: product.stocked ? '#333' : '#e74c3c' }}>
  32. {product.name}
  33. </span>
  34. {!product.stocked && (
  35. <span style={{ color: '#e74c3c', fontSize: 12, marginLeft: 8 }}>
  36. (缺货)
  37. </span>
  38. )}
  39. </td>
  40. <td>{product.price}</td>
  41. </tr>
  42. </Fragment>
  43. )
  44. })
  45. }
  46. return (
  47. <div>
  48. <h1>📦 商品列表</h1>
  49. <div style={{ margin: '16px 0', display: 'flex', gap: 16, alignItems: 'center' }}>
  50. <input type="text" placeholder='搜索商品名称...' onChange={(e) => dispatch(setFilterName(e.target.value))} style={{ padding: '8px 12px', borderRadius: 6, border: '1px solid #d9d9d9', width: 240 }} />
  51. <label style={{ cursor: 'pointer' }}>
  52. <input type="checkbox" style={{ marginRight: 6 }} onChange={(e) => dispatch(setShowStock(e.target.checked))} />仅显示有库存的商品</label>
  53. </div>
  54. <table border={1} cellPadding={12} style={{ borderCollapse: 'collapse', width: '100%' }}>
  55. <thead>
  56. <tr style={{ background: '#1a73e8', color: '#fff' }}>
  57. <th>商品名称</th>
  58. <th>商品价格</th>
  59. </tr>
  60. </thead>
  61. <tbody>
  62. {filterProducts.length === 0 ? (
  63. <tr>
  64. <td colSpan={2} style={{ textAlign: 'center', padding: 40, color: '#999' }}>
  65. 📭 暂无匹配商品
  66. </td>
  67. </tr>
  68. ) : (
  69. renderProduct()
  70. )}
  71. </tbody>
  72. </table>
  73. </div>
  74. )
  75. }
  76. export default Product;