jingrow/components/sidebar/Category.jsx
2025-06-17 15:23:37 +08:00

128 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { useEffect, useState } from "react";
import axios from "axios";
/**
* Product category sidebar component
* @param {string} componentName - component name
* @param {string} className - additional class names
*/
export default function Category({
componentName = "Category",
className = "",
}) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [activeCategory, setActiveCategory] = useState(null);
useEffect(() => {
async function fetchData() {
try {
setLoading(true);
// 1. 获取组件元数据
const metaRes = await axios.get("/api/get-component-data", {
params: { component_name: componentName },
});
const metaData = metaRes.data.data || {};
// 2. 获取分类树
if (metaData.p1 && metaData.p2) {
const catRes = await axios.get("/api/get-category", {
params: { pagetype: metaData.p1, name: metaData.p2 },
});
const categoryData = catRes.data.message?.data || {};
setData({
title: metaData.title || "Product Categories",
subtitle: metaData.subtitle || "",
slug: categoryData.slug,
items: categoryData.children || [],
});
}
} catch (err) {
console.error("获取分类数据失败:", err);
setError("Failed to fetch category data");
} finally {
setLoading(false);
}
}
fetchData();
}, [componentName]);
if (loading) return null;
if (error) return null;
if (!data) return null;
const handleCategoryClick = (categorySlug) => {
if (activeCategory === categorySlug) {
setActiveCategory(null);
} else {
setActiveCategory(categorySlug);
}
};
// 渲染分类列表
const renderCategories = (items, parentSlugs = []) => {
if (!items || !items.length) return null;
return (
<ul className="pl-0 list-none">
{items.map((item) => {
const hasChildren = Array.isArray(item.children) && item.children.length > 0;
const isActive = activeCategory === item.slug;
const currentPath = [...parentSlugs, item.slug];
return (
<li key={item.slug} className="nav-item">
<div
className="flex items-center justify-between cursor-pointer py-2"
onClick={() => {
if (hasChildren) handleCategoryClick(item.slug);
}}
>
<a
className="!text-[#60697b] hover:!text-[#22b573]"
href={`/${currentPath.join('/')}`}
onClick={e => e.stopPropagation()} // 阻止冒泡点击a只跳转
>
{item.name}
</a>
{hasChildren && (
<span className="ml-2 text-gray-400 hover:text-[#22b573]">{'>'}</span>
)}
</div>
{hasChildren && isActive && (
<div className="pl-4 sub-category">
<ul className="list-none pl-0">
{item.children.map((child) => (
<li key={child.slug} className="py-1">
<a
className="!text-[#60697b] hover:!text-[#22b573] text-sm"
href={`/${currentPath.join('/')}/${child.slug}`}
onClick={e => e.stopPropagation()}
>
{child.name}
</a>
</li>
))}
</ul>
</div>
)}
</li>
);
})}
</ul>
);
};
return (
<aside className={`hidden md:block lg:w-3/12 xl:w-3/12 sidebar px-8 py-8 bg-white rounded-xl shadow-md ${className}`}>
<div className="widget">
<h4 className="widget-title !mb-3">{data.title}</h4>
{data.subtitle && <div className="text-xs text-gray-500 mb-2">{data.subtitle}</div>}
{renderCategories(data.items, [data.slug])}
</div>
</aside>
);
}