antd树结构

一、场景实现

1、左侧为查询条件,查询条件为树和多选。点击查询条件在右上方显示搜索条件的内容,右上方查询条件 tag 删除后,左侧条件也对应删除。

2、树结构:默认第一层下所有节点都展开。

1、页面效果图

2、查询效果图

二、前端代码

1、Tree 组件

(1)实现方法一

import React, { useEffect, useState } from "react";
import { Tree, TreeProps } from "antd";interface FilterTreeProps {treeData: TreeNode[];value: string[];onChange: (values: string[]) => void;defaultExpandFirst?: boolean; // 是否默认展开第一条数据及其子级
}interface TreeNode {productLineCode: string;productLineName: string;children?: TreeNode[];
}interface SelectedNode {code: string;label: string;path: string;
}const { TreeNode } = Tree;const FilterTree = ({treeData,value,onChange,defaultExpandFirst = true,
}: FilterTreeProps) => {const [expandedKeys, setExpandedKeys] = useState<string[]>([]);/***  递归获取节点及其所有子节点的key*/const getAllKeys = (node: TreeNode): string[] => {if (!node) return [];const keys = [node.productLineCode]; // 当前节点// 递归添加子节点if (node.children && node.children.length > 0) {node.children.forEach((child: TreeNode) => {keys.push(...getAllKeys(child));});}return keys;};useEffect(() => {if (defaultExpandFirst && treeData.length > 0) {setExpandedKeys(getAllKeys(treeData[0]));}}, [treeData, defaultExpandFirst]);/** 收缩 */const onExpand = (expandedKeys: string[]) => {setExpandedKeys(expandedKeys as string[]);};/** 勾选 */const onCheck: TreeProps["onCheck"] = (selectKeys) => {const findParentNodes = (data: TreeNode[] = [],path: SelectedNode[] = []): SelectedNode[] => {return data.flatMap((item) => {const currentPath = [...path];const isParent = item.children && item.children.length > 0;if (isParent) {// 检查是否所有子节点都被选中const allChildrenSelected = item.children?.every((child) =>(selectKeys as string[]).includes(child.productLineCode));if (allChildrenSelected) {return [...currentPath,{code: item.productLineCode,label: item.productLineName,path: item.path,},];}// 递归处理子节点return findParentNodes(item.children, currentPath);}// 叶子节点处理return (selectKeys as string[]).includes(item.productLineCode)? [...currentPath,{code: item.productLineCode,label: item.productLineName,path: item.path,},]: [];});};const selectedNodes = findParentNodes(treeData);// console.log("勾选数据", selectedNodes);const params = {tags: selectedNodes, // 要显示的tags标签checkedValues: selectKeys, // 勾选的数据};onChange(params);};// 渲染树节点const renderTreeNodes = (data: TreeNode[]) => {return data.map((item) => {if (item.children && item.children.length > 0) {return (<TreeNodetitle={item.productLineName}key={item.productLineCode}style={{ lineHeight: "36px" }}>{renderTreeNodes(item.children)}</TreeNode>);}return (<TreeNode title={item.productLineName} key={item.productLineCode} />);});};return (<TreecheckablecheckedKeys={value}expandedKeys={expandedKeys}onCheck={onCheck}onExpand={onExpand}>{renderTreeNodes(treeData)}</Tree>);
};export default FilterTree;

(2)实现方法二

2、CheckBox 组件

import React from "react";
import { Checkbox } from "antd";interface FilterCheckboxProps {options: any[];value: string[];onChange: (values: string[]) => void;className?: string;itemClassName?: string;
}const FilterCheckbox = ({options,value,onChange,className,itemClassName,
}: FilterCheckboxProps) => {return (<Checkbox.Group className={className} value={value} onChange={onChange}>{options?.map((val: any) => (<Checkbox key={val.value} value={val.value} className={itemClassName}>{val.meaning}</Checkbox>))}</Checkbox.Group>);
};export default FilterCheckbox;

3、Search 组件

import React, { useEffect, useMemo, useState } from "react";
import Image from "next/image";
import { Input } from "antd";
import SearchIcon from "@/public/course/search.svg";
import styles from "../../index.module.scss";
import { getModelConfig } from "@/utils";
import { getPortalConfig } from "@/api/home";interface BannerProps {onSearch?: (goodsName: string) => void;
}const Banner: React.FC<BannerProps> = ({ onSearch }) => {const [searchValue, setSearchValue] = useState(""); // 搜索值const [configData, setConfigData] = useState([]); // 配置数据详情// banner图const bgLogo = useMemo(() => {// 获取顶级const father = getModelConfig("courseBackgroundImage", configData);// 获取子级const data = getModelConfig("courseBackgroundImage.picture",father?.childrenList);return data?.componentPicture || "";}, [configData]);/*** @description 获取配置列表*/const fetchConfig = async () => {const res = await getPortalConfig("zh_CN");if (res?.code === 200) {// 获取配置列表,过滤出'门户配置'下的组件const result = (res.data || []).filter((item: { componentPlate: string }) => item.componentPlate === "LESSONS");setConfigData(result);}};useEffect(() => {const fetchDataSequence = async () => {await fetchConfig();};fetchDataSequence();}, []);const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {const value = e.target.value;setSearchValue(value);// 当输入被清空时立即触发搜索if (value === "") {handleSearch();}};const handlePressEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {if (e.key === "Enter") {handleSearch();}};const handleSearch = () => {if (onSearch) {onSearch(searchValue.trim());}};return (<div className={styles.courseDetail_banner}>{/* 背景图 */}<Imagesrc={bgLogo}alt=""width={1920}height={280}style={{width: "100%",height: "280px",objectFit: "cover",}}unoptimizedloading="lazy"className={styles.courseDetail_banner_pic}/>{/* 内容 */}<div className={styles.courseDetail_banner_box}><div className={styles.courseDetail_banner_box_title}>汇川技术学堂</div>{/* 搜索 */}<div className={styles.courseDetail_banner_box_search}><Inputvariant="underlined"placeholder="你想了解..."value={searchValue}onChange={handleChange}onPressEnter={handlePressEnter}className={styles.courseDetail_banner_box_search_input}/><Imagesrc={SearchIcon}alt=""width={27}height={27}unoptimizedloading="lazy"onClick={handleSearch}/></div></div></div>);
};export default Banner;

4、Card组件

import React, { useEffect, useMemo, useState } from "react";
import Image from "next/image";
import styles from "../../index.module.scss";
import TypeIcon from "@/public/course/typeIcon.png";
import { getQueryValue } from "@/api/home";
import { objectToArr } from "@/utils";
import { filter } from "../../store";
import { DetailCardProps, OptionType } from "@/type/course";const Card: React.FC<{ list: DetailCardProps[] }> = ({ list = [] }) => {const [stages, setStages] = useState<OptionType[]>([]);useEffect(() => {// 阶段:值集const fetchStagesType = async () => {try {const res = await getQueryValue("INO_TAI_COURSE_STAGE");const result = objectToArr(res.data || []);setStages(result);} catch (error) {console.error("Error fetching title:", error);}};fetchStagesType();}, []);const stagesType = useMemo(() => stages, [stages]); // 阶段return (<>{list.map((item: DetailCardProps, index: number) => {return (<divkey={index}className={styles.courseDetail_content_right_card_item}>{/* 封面 */}<div className={styles.courseDetail_content_right_card_item_pic}><Imagesrc={item?.ossImgUrlCompressed}alt=""width={292}height={164}unoptimizedloading="lazy"className={styles.courseDetail_content_right_card_item_pic}/></div><div className={styles.courseDetail_content_right_card_item_box}><divclassName={styles.courseDetail_content_right_card_item_box_title}>{item.goodsName}</div><divclassName={styles.courseDetail_content_right_card_item_box_info}>{/* 阶段 */}<divclassName={styles.courseDetail_content_right_card_item_box_info_left}><Imagesrc={TypeIcon}alt=""width={13}height={13}unoptimizedloading="lazy"/>{filter(stagesType, item.stage)}</div>{/* <div>iFA开发者</div> */}</div>{/* 价格:如果为0的话显示'免费' */}<divclassName={styles.courseDetail_content_right_card_item_box_type}style={{ marginTop: "28px" }}>{item.priceLow === 0 ? "免费" : `¥${item.priceLow}`}</div></div></div>);})}</>);
};
export default Card;

5、完整代码(非最新版,待更新)

"use client";import React, { useEffect, useState } from "react";
import Image from "next/image";
import { CloseOutlined } from "@ant-design/icons";
import Layout from "@/components/Layout/index";
import Card from "./components/Card/main";
import Search from "./components/Search/main";
import FilterCheckbox from "./components/CheckBox/main";
import FilterTree from "./components/Tree/main";
import styles from "./index.module.scss";
import { objectToArr } from "@/utils";
import { getQueryValue } from "@/api/home";
import DeleteIcon from "@/public/course/delete.png";
import { Pagination } from "antd";
import { getBusinessConfig, postCourseList } from "@/api/course";
import {ChooseItem,CourseItem,DetailCardProps,OptionType,PaginationState,SearchItem,
} from "@/type/course";
import { searchParams } from "./store";
import EmptyIcon from "@/public/empty.png";const CourseDetail: React.FC = () => {const [table, setTable] = useState<DetailCardProps[]>([]); // table列表const [goodsName, setGoodsName] = useState<string>(""); // 课程名称const [chooseList, setChooseList] = useState<ChooseItem[]>([]); // 新增:已选条件列表// 存储各类型的选中值const [selectedValues, setSelectedValues] = useState<Record<string, string[]>>({});// 分页状态const [pagination, setPagination] = useState<PaginationState>({currentPage: 1,pageSize: 12,total: 0,});// 搜索条件const [searchList, setSearchList] = useState<SearchItem[]>([{ name: "业务模块", value: "modules", query: "businessModel", list: [] },{ name: "阶段", value: "stages", query: "INO_TAI_COURSE_STAGE", list: [] },{name: "内容类型",value: "contentTypes",query: "INO_TAI_COURSE_TYPE",list: [],},{name: "价格",value: "priceRanges",query: "INO_TAI_COURSE_PRICE",list: [],},{name: "课程类型",value: "courseTypes",query: "INO_TAI_COURSE_SUBJECT_TYPE",list: [],},
]);/*** 获取课程列表* @param page - 当前页码(1-based)* @param pageSize - 每页大小*/const fetchData = async (page = 1, pageSize = 12) => {// 必传项const requireParams = {sellType: "independently", // 付费类型(C端只显示:独立售卖)isStopSell: "N", // 是否停售(C端显示0)isForbid: "N", // 商品是否被封禁(C端显示0)};// 可选项const params: CourseItem = {page: page - 1, // 转换为0-basedsize: pageSize,...(goodsName !== undefined ? { goodsName } : {}), // 课程名称};// 添加已选条件到查询参数const otherParams = {...Object.entries(selectedValues).reduce((acc, [type, values]) => {if (values && values.length > 0) {acc[type] = values; // 多个值用数组}return acc;}, {} as Record<string, string[]>),};// console.log("otherParams", otherParams);const resultParams = {// ...requireParams,...params,...otherParams,};// console.log("查询条件", resultParams);try {const res = await postCourseList(resultParams);if (res.data) {setTable(res.data.content || []);// 更新分页状态(总记录数、当前页、每页大小)setPagination({total: res.data.totalElements || 0, // 总记录数currentPage: page, // 前端显示的当前页(1-based)pageSize: res.data.size || 12, // 后端返回的每页大小});}} catch (error) {console.error("获取课程列表失败:", error);}};const handleTreeChange = (type: string, checkedValues: any) => {console.log("树结构处理", type, checkedValues);};/*** 处理多选框变化* @param type - 条件类型* @param checkedValues - 选中的值数组*/const handleCheckboxChange = (type: string, checkedValues: any[]) => {// 更新选中值状态setSelectedValues((prev) => ({...prev,[type]: checkedValues,}));// 获取当前条件的配置const currentCondition = searchList.find((item) => item.value === type);if (!currentCondition) return;// 更新已选条件列表setChooseList((prev) => {// 先移除当前类型的所有已选条件const filtered = prev.filter((item) => item.type !== type);// 如果有选中的值,则添加新的条件if (checkedValues.length > 0) {const newItems = checkedValues.map((value) => {const option = currentCondition.list.find((item: any) => item.value === value);return {type,value,meaning: option?.meaning || value,};});return [...filtered, ...newItems];}return filtered;});};/*** 移除单个已选条件* @param type - 条件类型* @param value - 要移除的值*/const removeCondition = (type: string, value: string) => {setSelectedValues((prev) => ({...prev,[type]: prev[type]?.filter((v) => v !== value) || [],}));setChooseList((prev) =>prev.filter((item) => !(item.type === type && item.value === value)));};/*** 清空所有已选条件*/const clearAllConditions = () => {setSelectedValues({});setChooseList([]);};/*** 加载筛选条件数据*/useEffect(() => {const fetchOptions = async () => {// 1. 处理常规接口请求const normalItems = searchList.filter((item) => item.query && item.query !== "businessModel");const normalPromises = normalItems.map((item: any) =>getQueryValue(item.query).then((res) => ({key: item.value,data: objectToArr(res.data || []).sort((a, b) => a.orderSeq - b.orderSeq),})));// 2. 处理特殊接口请求const businessItem = searchList.find((item) => item.query === "businessModel");const businessPromise = businessItem? getBusinessConfig().then((res) => ({key: businessItem.value,data: objectToArr(res.data || []).sort((a, b) => a.orderSeq - b.orderSeq),})): Promise.resolve({ key: "", data: [] }); // 若无businessModel,返回空结果try {const [normalResults, businessResult] = await Promise.all([Promise.all(normalPromises),businessPromise,]);// 合并结果const resultMap = [...normalResults, businessResult].reduce((map, result) => {if (result.key) map[result.key] = result.data;return map;},{} as Record<string, OptionType[]>);setSearchList((prev) =>prev.map((item) => ({...item,list: resultMap[item.value] || [],})));} catch (error) {console.error("加载筛选条件失败:", error);}};fetchOptions();}, []);// 初始数据加载useEffect(() => {(async function () {await fetchData();})();}, [goodsName, chooseList]);return (<><Layout><div className={styles.courseDetail}><SearchonSearch={(searchText) => {setGoodsName(searchText);}}/><div className={styles.courseDetail_content}>{/* 左侧筛选栏 */}<div className={styles.courseDetail_content_left}><div className={styles.courseDetail_content_left_title}>筛选</div>{/* 查询条件 */}{searchList.map((item) => (<React.Fragment key={item.value}><divclassName={`${styles.courseDetail_content_left_title} ${styles.courseDetail_content_left_subTitle}`}>{item.name}</div>{/* 业务模块使用Tree组件,其他使用Checkbox组件 */}{item.query === "businessModel" ? (<><FilterTreetreeData={item.list || []}value={selectedValues[item.value] || []}onChange={(values) =>handleCheckboxChange(item.value, values)}/></>) : (<><FilterCheckboxoptions={item.list || []}value={selectedValues[item.value] || []}onChange={(values) =>handleCheckboxChange(item.value, values)}className={styles.courseDetail_content_left_checkbox}itemClassName={styles.courseDetail_content_left_checkbox_item}/></>)}</React.Fragment>))}</div>{/* 右侧 */}<div className={styles.courseDetail_content_right}><div className={styles.courseDetail_content_right_main}>{/* 查询条件:标签 */}<div className={styles.courseDetail_content_right_search}><divclassName={styles.courseDetail_content_right_search_left}>{/* 展示已选条件 */}{chooseList.map((item) => (<divkey={`${item.type}-${item.value}`}className={styles.courseDetail_content_right_search_left_tags}>{item.meaning}<CloseOutlinedstyle={{fontSize: "10px",color: "#8F8F8F",marginLeft: 4,}}onClick={() => removeCondition(item.type, item.value)}/></div>))}{/* 清空所有按钮 */}{chooseList.length > 0 && (<divclassName={styles.courseDetail_content_right_search_left_tags}onClick={clearAllConditions}><Imagesrc={DeleteIcon}alt="清空"width={10}height={11}unoptimizedloading="lazy"/><span style={{ marginLeft: 4 }}>清空</span></div>)}</div><divclassName={styles.courseDetail_content_right_search_right}>找到全部相关内容:{pagination.total}</div></div>{/* 课程卡片区域 */}{table?.length > 0 ? (<div className={styles.courseDetail_content_right_card}><Card list={table} /></div>) : (<div className={styles.courseDetail_empty}><Imagesrc={EmptyIcon}alt="empty"width={165}height={115}unoptimizedloading="lazy"/><div className={styles.courseDetail_empty_desc}>暂无课程,看看其他的吧~</div></div>)}</div>{/* 分页 */}<div className={styles.courseDetail_content_right_page}><Paginationtotal={pagination.total || 0}current={pagination.currentPage} // 前端显示的当前页(1-based)pageSize={pagination.pageSize}showSizeChangershowQuickJumpershowTotal={(total) => `共 ${total} 条记录`}onChange={(page) => fetchData(page)} // 页码变更时(1-based)onShowSizeChange={(currentPage, pageSize) => fetchData(currentPage, pageSize) // 切换每页大小后从第一页开始}/></div></div></div></div></Layout></>);
};
export default CourseDetail;

5、css样式

// 内容一行,超出显示省略号
@mixin ellipsis-one-lines {overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 1;-webkit-box-orient: vertical;
}// 内容两行,超出显示省略号
@mixin ellipsis-two-lines {overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;
}.courseDetail {font-family: "阿里巴巴普惠体";width: 100%;background: #ffffff;&_banner {width: 100%;height: 280px;position: relative;display: flex;&_pic {position: absolute;inset: 0;}&_box {width: 1226px;margin: 0 auto;position: relative;display: flex;flex-direction: column;align-items: center;justify-content: center;&_title {color: #0c1a34;font-size: 48px;line-height: 70px;font-weight: 700;margin-bottom: 24px;}// 搜索&_search {width: 960px;height: 56px;border-radius: 4px;box-shadow: 0px 5px 12px 4px rgba(0, 0, 0, 0.05),0px 3px 6px 0px rgba(0, 0, 0, 0.08),0px 1px 2px -2px rgba(0, 0, 0, 0.12);background: white;padding: 12px 24px 12px 12px;box-sizing: border-box;display: flex;gap: 8px;&_input {flex: 1;border: none;}img {&:hover {cursor: pointer;}}}}}&_content {width: 1226px;margin: 0 auto;padding: 84px 0 114px 0;display: flex;flex-direction: row;gap: 24px;&_left {width: 295px;&_title {font-size: 18px;font-weight: bold;color: #222222;border-bottom: 1px solid #dee3e8;line-height: 48px;padding: 0 16px;letter-spacing: 0px;}&_subTitle {font-size: 16px;}// 树// 多选框&_checkbox {display: flex;flex-direction: column;padding: 0 16px;box-sizing: border-box;// gap: 8px;&_item {line-height: 40px;}}}&_right {flex: 1;// 查询条件:标签&_search {display: flex;justify-content: space-between;gap: 16px;&_left {display: flex;flex-wrap: wrap;gap: 8px;&_tags {color: #222222;font-size: 12px;line-height: 24px;padding: 0 8px;background: #f5f5f5;display: flex;align-items: center;gap: 4px;}}&_right {color: #9099ac;font-weight: 400;font-size: 14px;line-height: 20px;}}// 卡片&_card {width: 100%;display: flex;flex-wrap: wrap;gap: 16px;padding-top: 15px;margin-top: 15px;border-top: 1px solid #dee3e8;&_item {width: calc((100% - 32px) / 3);flex-basis: calc((100% - 32px) / 3);border-radius: 15px;background: white;box-shadow: 0px 1.67px 16.7px 0px rgba(0, 0, 0, 0.1);&:hover {cursor: pointer;box-shadow: 0px 18px 32px 16px rgba(0, 0, 0, 0.03),0px 12px 24px 0px rgba(0, 0, 0, 0.05),0px 8px 16px -8px rgba(0, 0, 0, 0.06);}&_pic {width: 292px;height: 164px;border-radius: 11.01px 11.01px 0px 0px;}&_box {padding: 12px;&_title {color: #222222;font-size: 16px;font-weight: bold;line-height: 24px;height: 48px;@include ellipsis-two-lines;}&_info {display: flex;align-items: center;justify-content: space-between;font-size: 12px;color: #8c8c8c;line-height: 20px;margin-top: 4px;&_left {display: flex;align-items: center;gap: 4px;}}&_type {color: #222222;font-size: 16px;font-weight: bold;line-height: 24px;margin-bottom: 8px;}}}}// 分页&_page {display: flex;justify-content: flex-end;margin-top: 32px;}}}// 空数据&_empty {width: 100%;padding: 90px 0;box-sizing: border-box;display: flex;flex-direction: column;align-items: center;&_desc {font-size: 14px;color: #788295;line-height: 19px;margin-top: 27px;}}
}

三、后端返回JSON

[{"creationDate": "2025-05-19 16:18:49","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:26:17","lastUpdatedBy": 13937,"objectVersionNumber": 2,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQTEBt6f+NtV7DQiMXR9/fGHZSWroRqcOPk1MTPLSV5VE=","id": 199,"productLineCode": "068607","productLineName": "karla","productLineLevel": 1,"productLineSort": 1,"path": "068607","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:18:56","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:21:29","lastUpdatedBy": 13937,"objectVersionNumber": 2,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqEtpLwGY7lxCOrle/21VpcI=","id": 200,"productLineCode": "788763","productLineName": "demo","productLineLevel": 2,"productLineSort": 1,"parentCode": "068607","path": "068607/788763","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:19:08","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:21:20","lastUpdatedBy": 13937,"objectVersionNumber": 2,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqJgDxrQ9Pf5/U+hdOUL/DYQ=","id": 202,"productLineCode": "185799","productLineName": "小朋友","productLineLevel": 3,"productLineSort": 1,"parentCode": "788763","path": "068607/788763/185799","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:19:45","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:19:45","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqNISAJXY9gOeNcmlflkR5po=","id": 205,"productLineCode": "220944","productLineName": "小宝宝","productLineLevel": 4,"productLineSort": 1,"parentCode": "185799","path": "068607/788763/185799/220944","tenantId": 0,"matched": false,"children": []}]},{"creationDate": "2025-05-19 16:19:22","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:20:35","lastUpdatedBy": 13937,"objectVersionNumber": 2,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqPJvYv6jT8jvuZuYoqlaew4=","id": 203,"productLineCode": "385121","productLineName": "家庭成员","productLineLevel": 3,"productLineSort": 2,"parentCode": "788763","path": "068607/788763/385121","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:19:55","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:19:55","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqKcdVFMAFlWjlvwB2owvxf8=","id": 206,"productLineCode": "507563","productLineName": "爸","productLineLevel": 4,"productLineSort": 1,"parentCode": "385121","path": "068607/788763/385121/507563","tenantId": 0,"matched": false,"children": []},{"creationDate": "2025-05-19 16:20:02","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:20:02","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqB0JnEiN7gP29YaDjqF2sys=","id": 207,"productLineCode": "079729","productLineName": "妈","productLineLevel": 4,"productLineSort": 1,"parentCode": "385121","path": "068607/788763/385121/079729","tenantId": 0,"matched": false,"children": []},{"creationDate": "2025-05-19 16:20:13","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:20:13","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqHCRKHEIQQwrjFTkTwNdkJw=","id": 208,"productLineCode": "082499","productLineName": "爷爷","productLineLevel": 4,"productLineSort": 3,"parentCode": "385121","path": "068607/788763/385121/082499","tenantId": 0,"matched": false,"children": []},{"creationDate": "2025-05-19 16:20:22","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:20:22","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqHZSWroRqcOPk1MTPLSV5VE=","id": 209,"productLineCode": "334232","productLineName": "奶奶","productLineLevel": 4,"productLineSort": 4,"parentCode": "385121","path": "068607/788763/385121/334232","tenantId": 0,"matched": false,"children": []}]},{"creationDate": "2025-05-19 16:19:33","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:20:51","lastUpdatedBy": 13937,"objectVersionNumber": 2,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqH862sHidVIsCLoA5mqI2Zc=","id": 204,"productLineCode": "410177","productLineName": "水果","productLineLevel": 3,"productLineSort": 3,"parentCode": "788763","path": "068607/788763/410177","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:20:44","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:20:44","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhUtpLwGY7lxCOrle/21VpcI=","id": 210,"productLineCode": "514006","productLineName": "苹果","productLineLevel": 4,"productLineSort": 1,"parentCode": "410177","path": "068607/788763/410177/514006","tenantId": 0,"matched": false,"children": []},{"creationDate": "2025-05-19 16:20:59","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:20:59","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhXXzRoERUkkc2i2OTyqu/QI=","id": 211,"productLineCode": "350970","productLineName": "菠萝","productLineLevel": 4,"productLineSort": 2,"parentCode": "410177","path": "068607/788763/410177/350970","tenantId": 0,"matched": false,"children": []},{"creationDate": "2025-05-19 16:21:08","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:21:08","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhZgDxrQ9Pf5/U+hdOUL/DYQ=","id": 212,"productLineCode": "367594","productLineName": "香蕉","productLineLevel": 4,"productLineSort": 5,"parentCode": "410177","path": "068607/788763/410177/367594","tenantId": 0,"matched": false,"children": []}]}]},{"creationDate": "2025-05-19 16:19:02","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:21:38","lastUpdatedBy": 13937,"objectVersionNumber": 2,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQM8g/tDo7jW7Ku6QInBMZqHXzRoERUkkc2i2OTyqu/QI=","id": 201,"productLineCode": "115960","productLineName": "汽车","productLineLevel": 2,"productLineSort": 1,"parentCode": "068607","path": "068607/115960","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:21:45","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:21:45","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhfJvYv6jT8jvuZuYoqlaew4=","id": 213,"productLineCode": "284494","productLineName": "国产","productLineLevel": 3,"productLineSort": 1,"parentCode": "115960","path": "068607/115960/284494","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:22:19","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:22:19","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhR0JnEiN7gP29YaDjqF2sys=","id": 217,"productLineCode": "569856","productLineName": "长城","productLineLevel": 4,"productLineSort": 1,"parentCode": "284494","path": "068607/115960/284494/569856","tenantId": 0,"matched": false,"children": []}]},{"creationDate": "2025-05-19 16:21:52","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:21:52","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhX862sHidVIsCLoA5mqI2Zc=","id": 214,"productLineCode": "564860","productLineName": "国外","productLineLevel": 3,"productLineSort": 2,"parentCode": "115960","path": "068607/115960/564860","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:22:05","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:22:05","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhdISAJXY9gOeNcmlflkR5po=","id": 215,"productLineCode": "326208","productLineName": "沃尔沃","productLineLevel": 4,"productLineSort": 1,"parentCode": "564860","path": "068607/115960/564860/326208","tenantId": 0,"matched": false,"children": []},{"creationDate": "2025-05-19 16:22:12","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:22:12","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhacdVFMAFlWjlvwB2owvxf8=","id": 216,"productLineCode": "617395","productLineName": "宝马","productLineLevel": 4,"productLineSort": 3,"parentCode": "564860","path": "068607/115960/564860/617395","tenantId": 0,"matched": false,"children": []}]}]},{"creationDate": "2025-05-19 16:22:27","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:22:27","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhXCRKHEIQQwrjFTkTwNdkJw=","id": 218,"productLineCode": "153878","productLineName": "你好呀","productLineLevel": 2,"productLineSort": 2,"parentCode": "068607","path": "068607/153878","tenantId": 0,"matched": false,"children": []}]},{"creationDate": "2025-05-09 18:40:11","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:22:58","lastUpdatedBy": 13937,"objectVersionNumber": 3,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQwHGwJ4ahmn50+LyPk0m4FH862sHidVIsCLoA5mqI2Zc=","id": 184,"productLineCode": "395902","productLineName": "课程","productLineLevel": 1,"productLineSort": 2,"path": "395902","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:23:14","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:23:14","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQQltZlT7MnufgSfHOIXwHZ5gDxrQ9Pf5/U+hdOUL/DYQ=","id": 222,"productLineCode": "604957","productLineName": "数学","productLineLevel": 2,"productLineSort": 2,"parentCode": "395902","path": "395902/604957","tenantId": 0,"matched": false,"children": []},{"creationDate": "2025-05-19 16:23:09","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:23:09","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQQltZlT7MnufgSfHOIXwHZ3XzRoERUkkc2i2OTyqu/QI=","id": 221,"productLineCode": "104885","productLineName": "语文","productLineLevel": 2,"productLineSort": 2,"parentCode": "395902","path": "395902/104885","tenantId": 0,"matched": false,"children": []}]},{"creationDate": "2025-05-13 14:24:05","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:22:38","lastUpdatedBy": 13937,"objectVersionNumber": 2,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQTEBt6f+NtV7DQiMXR9/fGB0JnEiN7gP29YaDjqF2sys=","id": 197,"productLineCode": "422225","productLineName": "国家","productLineLevel": 1,"productLineSort": 3,"path": "422225","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-19 16:22:43","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:22:43","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQpUihnaRAYlwAQ/WFvF1xhXZSWroRqcOPk1MTPLSV5VE=","id": 219,"productLineCode": "170090","productLineName": "中国","productLineLevel": 2,"productLineSort": 1,"parentCode": "422225","path": "422225/170090","tenantId": 0,"matched": false,"children": []},{"creationDate": "2025-05-19 16:22:49","createdBy": 13937,"lastUpdateDate": "2025-05-19 16:22:49","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQQltZlT7MnufgSfHOIXwHZ0tpLwGY7lxCOrle/21VpcI=","id": 220,"productLineCode": "833410","productLineName": "美国","productLineLevel": 2,"productLineSort": 2,"parentCode": "422225","path": "422225/833410","tenantId": 0,"matched": false,"children": []}]},{"creationDate": "2025-05-09 18:48:32","createdBy": 13937,"lastUpdateDate": "2025-05-13 14:24:09","lastUpdatedBy": 13937,"objectVersionNumber": 2,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQTEBt6f+NtV7DQiMXR9/fGEtpLwGY7lxCOrle/21VpcI=","id": 190,"productLineCode": "028284","productLineName": "4","productLineLevel": 1,"productLineSort": 4,"path": "028284","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-09 18:48:38","createdBy": 13937,"lastUpdateDate": "2025-05-09 18:48:38","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQTEBt6f+NtV7DQiMXR9/fGHXzRoERUkkc2i2OTyqu/QI=","id": 191,"productLineCode": "033804","productLineName": "3","productLineLevel": 2,"productLineSort": 3,"parentCode": "028284","path": "028284/033804","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-09 18:48:46","createdBy": 13937,"lastUpdateDate": "2025-05-09 18:48:46","lastUpdatedBy": 13937,"objectVersionNumber": 1,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQTEBt6f+NtV7DQiMXR9/fGJgDxrQ9Pf5/U+hdOUL/DYQ=","id": 192,"productLineCode": "062078","productLineName": "2","productLineLevel": 3,"productLineSort": 2,"parentCode": "033804","path": "028284/033804/062078","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-09 18:48:51","createdBy": 13937,"lastUpdateDate": "2025-05-09 18:52:35","lastUpdatedBy": 13937,"objectVersionNumber": 3,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQTEBt6f+NtV7DQiMXR9/fGPJvYv6jT8jvuZuYoqlaew4=","id": 193,"productLineCode": "065263","productLineName": "绑定课程四级","productLineLevel": 4,"productLineSort": 1,"parentCode": "062078","path": "028284/033804/062078/065263","tenantId": 0,"matched": false,"children": [{"creationDate": "2025-05-09 18:49:01","createdBy": 13937,"lastUpdateDate": "2025-05-09 18:52:49","lastUpdatedBy": 13937,"objectVersionNumber": 3,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQTEBt6f+NtV7DQiMXR9/fGH862sHidVIsCLoA5mqI2Zc=","id": 194,"productLineCode": "708130","productLineName": "绑定课程五级","productLineLevel": 5,"productLineSort": 1,"parentCode": "065263","path": "028284/033804/062078/065263/708130","tenantId": 0,"matched": false,"children": []}]}]}]}]},{"creationDate": "2025-05-09 14:36:42","createdBy": 41344,"lastUpdateDate": "2025-05-19 16:26:21","lastUpdatedBy": 13937,"objectVersionNumber": 5,"_token": "vF3QEsJKNjXBOytbocJJJ029kVE6+U/Z7BkBLEAPhEwFuzOtisxAqcHVn8vKcuFQjdq6zFI0rq1LFywvSox31tISAJXY9gOeNcmlflkR5po=","id": 175,"productLineCode": "876514","productLineName": "公司","productLineLevel": 1,"productLineSort": 6,"path": "876514","tenantId": 0,"matched": false,"children": []}
]

要实现:默认第一条数据下所有的子集都展开。

目前只实现了:

应实现效果:

默认第一条数据的所有子级都显示代码:

import React, { useState } from "react";
import { Tree, TreeProps } from "antd";interface FilterTreeProps {treeData: any[];value: string[];onChange: (values: string[]) => void;defaultExpandFirst?: boolean; // 是否默认展开第一条数据及其子级
}const { TreeNode } = Tree;const FilterTree = ({treeData,value,onChange,defaultExpandFirst = true,
}: FilterTreeProps) => {const [expandedKeys, setExpandedKeys] = useState<string[]>([]);/** 递归获取节点及其所有子节点的key */const getAllKeys = (node: any): string[] => {if (!node) return [];const keys = [node.productLineCode]; // 当前节点// 递归添加子节点if (node.children && node.children.length > 0) {node.children.forEach((child: any) => {keys.push(...getAllKeys(child));});}return keys;};React.useEffect(() => {if (defaultExpandFirst && treeData.length > 0) {setExpandedKeys(getAllKeys(treeData[0]));}}, [treeData, defaultExpandFirst]);const onCheck: TreeProps["onCheck"] = (checkedKeys, info) => {// console.log("onCheck", checkedKeys, info);// 这里的数据,勾选的数据都添加checkStatus: true的状态,打印出treeDataconsole.log("勾选的数据", info.checkedNodes);onChange(checkedKeys);};const onExpand = (expandedKeys: string[]) => {setExpandedKeys(expandedKeys);};// 渲染树节点const renderTreeNodes = (data: any[]) => {return data.map((item) => {if (item.children && item.children.length > 0) {return (<TreeNodetitle={item.productLineName}key={item.productLineCode}style={{ lineHeight: "36px" }}>{renderTreeNodes(item.children)}</TreeNode>);}return (<TreeNode title={item.productLineName} key={item.productLineCode} />);});};return (<TreecheckablecheckedKeys={value}expandedKeys={expandedKeys}onCheck={onCheck}onExpand={onExpand}>{renderTreeNodes(treeData)}</Tree>);
};export default FilterTree;

打印出来没问题,所有代码:

"use client";import React, { useEffect, useState } from "react";
import Image from "next/image";
import { CloseOutlined } from "@ant-design/icons";
import Layout from "@/components/Layout/index";
import Card from "./components/Card/main";
import Search from "./components/Search/main";
import FilterCheckbox from "./components/CheckBox/main";
import FilterTree from "./components/Tree/main";
import styles from "./index.module.scss";
import { objectToArr } from "@/utils";
import { getQueryValue } from "@/api/home";
import DeleteIcon from "@/public/course/delete.png";
import { Pagination } from "antd";
import { getBusinessConfig, postCourseList } from "@/api/course";
import {ChooseItem,CourseItem,DetailCardProps,OptionType,PaginationState,SearchItem,
} from "@/type/course";const CourseDetail: React.FC = () => {const [table, setTable] = useState<DetailCardProps[]>([]); // table列表const [goodsName, setGoodsName] = useState<string>(""); // 课程名称const [chooseList, setChooseList] = useState<ChooseItem[]>([]); // 新增:已选条件列表const [selectedValues, setSelectedValues] = useState<Record<string, string[]>>({}); // 存储各类型的选中值// 分页状态const [pagination, setPagination] = useState<PaginationState>({currentPage: 1,pageSize: 12,total: 0,});// 搜索条件const [searchList, setSearchList] = useState<SearchItem[]>([{ name: "业务模块", value: "modules", query: "businessModel", list: [] },{ name: "阶段", value: "stages", query: "INO_TAI_COURSE_STAGE", list: [] },{name: "内容类型",value: "contentTypes",query: "INO_TAI_COURSE_TYPE",list: [],},{name: "价格",value: "priceRanges",query: "INO_TAI_COURSE_PRICE",list: [],},{name: "课程类型",value: "courseTypes",query: "INO_TAI_COURSE_SUBJECT_TYPE",list: [],},]);/*** 获取课程列表* @param page - 当前页码(1-based)* @param pageSize - 每页大小*/const fetchData = async (page = 1, pageSize = 12) => {// 必传项const requireParams = {sellType: "independently", // 付费类型(C端只显示:独立售卖)isStopSell: "N", // 是否停售(C端显示0)isForbid: "N", // 商品是否被封禁(C端显示0)};// 可选项const params: CourseItem = {page: page - 1, // 转换为0-basedsize: pageSize,...(goodsName !== undefined ? { goodsName } : {}), // 课程名称};// 添加已选条件到查询参数const otherParams = {...Object.entries(selectedValues).reduce((acc, [type, values]) => {if (values && values.length > 0) {acc[type] = values; // 多个值用数组}return acc;}, {} as Record<string, string[]>),};console.log("otherParams", otherParams);// console.log("查询条件", params);try {const res = await postCourseList({// ...requireParams,...params,// ...otherParams,});// console.log("????", res.data);if (res.data) {setTable(res.data.content || []);// 更新分页状态(总记录数、当前页、每页大小)setPagination({total: res.data.totalElements || 0, // 总记录数currentPage: page, // 前端显示的当前页(1-based)pageSize: res.data.size || 12, // 后端返回的每页大小});}} catch (error) {console.error("获取课程列表失败:", error);}};/*** 处理多选框变化* @param type - 条件类型* @param checkedValues - 选中的值数组*/const handleCheckboxChange = (type: string, checkedValues: any[]) => {// 更新选中值状态setSelectedValues((prev) => ({...prev,[type]: checkedValues,}));// 获取当前条件的配置const currentCondition = searchList.find((item) => item.value === type);if (!currentCondition) return;// 更新已选条件列表setChooseList((prev) => {// 先移除当前类型的所有已选条件const filtered = prev.filter((item) => item.type !== type);// 如果有选中的值,则添加新的条件if (checkedValues.length > 0) {const newItems = checkedValues.map((value) => {const option = currentCondition.list.find((item: any) => item.value === value);return {type,value,meaning: option?.meaning || value,};});return [...filtered, ...newItems];}return filtered;});};/*** 移除单个已选条件* @param type - 条件类型* @param value - 要移除的值*/const removeCondition = (type: string, value: string) => {setSelectedValues((prev) => ({...prev,[type]: prev[type]?.filter((v) => v !== value) || [],}));setChooseList((prev) =>prev.filter((item) => !(item.type === type && item.value === value)));};/*** 清空所有已选条件*/const clearAllConditions = () => {setSelectedValues({});setChooseList([]);};/*** 加载筛选条件数据*/useEffect(() => {const fetchOptions = async () => {// 1. 处理常规接口请求const normalItems = searchList.filter((item) => item.query && item.query !== "businessModel");const normalPromises = normalItems.map((item: any) =>getQueryValue(item.query).then((res) => ({key: item.value,data: objectToArr(res.data || []).sort((a, b) => a.orderSeq - b.orderSeq),})));// 2. 处理特殊接口请求const businessItem = searchList.find((item) => item.query === "businessModel");const businessPromise = businessItem? getBusinessConfig().then((res) => ({key: businessItem.value,data: objectToArr(res.data || []).sort((a, b) => a.orderSeq - b.orderSeq),})): Promise.resolve({ key: "", data: [] }); // 若无businessModel,返回空结果try {const [normalResults, businessResult] = await Promise.all([Promise.all(normalPromises),businessPromise,]);// 合并结果const resultMap = [...normalResults, businessResult].reduce((map, result) => {if (result.key) map[result.key] = result.data;return map;},{} as Record<string, OptionType[]>);setSearchList((prev) =>prev.map((item) => ({...item,list: resultMap[item.value] || [],})));} catch (error) {console.error("加载筛选条件失败:", error);}};fetchOptions();}, []);// 初始数据加载useEffect(() => {(async function () {await fetchData();})();}, [goodsName, chooseList]);return (<><Layout><div className={styles.courseDetail}><SearchonSearch={(searchText) => {// console.log("Searching for:", searchText);setGoodsName(searchText);}}/><div className={styles.courseDetail_content}>{/* 左侧筛选栏 */}<div className={styles.courseDetail_content_left}><div className={styles.courseDetail_content_left_title}>筛选</div>{/* 查询条件 */}{searchList.map((item) => (<React.Fragment key={item.value}><divclassName={`${styles.courseDetail_content_left_title} ${styles.courseDetail_content_left_subTitle}`}>{item.name}</div>{/* 业务模块使用Tree组件,其他使用Checkbox组件 */}{item.query === "businessModel" ? (<><FilterTreetreeData={item.list || []}value={selectedValues[item.value] || []}onChange={(values) =>handleCheckboxChange(item.value, values)}className={styles.courseDetail_content_left_tree}/></>) : (<><FilterCheckboxoptions={item.list || []}value={selectedValues[item.value] || []}onChange={(values) =>handleCheckboxChange(item.value, values)}className={styles.courseDetail_content_left_checkbox}itemClassName={styles.courseDetail_content_left_checkbox_item}/></>)}</React.Fragment>))}</div>{/* 右侧 */}<div className={styles.courseDetail_content_right}>{/* 查询条件:标签 */}<div className={styles.courseDetail_content_right_search}><div className={styles.courseDetail_content_right_search_left}>{/* 展示已选条件 */}{chooseList.map((item) => (<divkey={`${item.type}-${item.value}`}className={styles.courseDetail_content_right_search_left_tags}>{item.meaning}<CloseOutlinedstyle={{fontSize: "10px",color: "#8F8F8F",marginLeft: 4,}}onClick={() => removeCondition(item.type, item.value)}/></div>))}{/* 清空所有按钮 */}{chooseList.length > 0 && (<divclassName={styles.courseDetail_content_right_search_left_tags}onClick={clearAllConditions}><Imagesrc={DeleteIcon}alt="清空"width={10}height={11}unoptimizedloading="lazy"/><span style={{ marginLeft: 4 }}>清空</span></div>)}</div><div className={styles.courseDetail_content_right_search_right}>找到全部相关内容:{pagination.total}</div></div>{/* 课程卡片区域 */}<div className={styles.courseDetail_content_right_card}><Card list={table} /></div>{/* 分页 */}<div className={styles.courseDetail_content_right_page}><Paginationtotal={pagination.total || 0}current={pagination.currentPage} // 前端显示的当前页(1-based)pageSize={pagination.pageSize}showSizeChangershowQuickJumpershowTotal={(total) => `共 ${total} 条记录`}onChange={(page) => fetchData(page)} // 页码变更时(1-based)onShowSizeChange={(currentPage, pageSize) => fetchData(currentPage, pageSize) // 切换每页大小后从第一页开始}/></div></div></div></div></Layout></>);
};
export default CourseDetail;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/81584.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins 安装与配置指南

Jenkins 安装与配置指南&#xff08;MD 示例&#xff09; markdown Jenkins 安装与配置指南 ## 一、环境准备 1. **系统要求** - 操作系统&#xff1a;Linux/macOS/Windows - Java 版本&#xff1a;JDK 8 或更高&#xff08;建议 JDK 11&#xff09;2. **安装方式** - **L…

[Linux性能优化] 线程卡顿优化。Linux加入USB(HID)热插拔线程占用CPU优化。Linux中CPU使用率过高优化

文章目录 [Linux性能优化] 线程卡顿优化。0、省流版本一、问题定位&#xff1a;CPU 资源分析二、线程卡顿现场复现线程优化前图片 三、线程卡顿优化方向1.如果是轮询方式2.如果是事件驱动方式 四、修改方式线程优化后图片 [Linux性能优化] 线程卡顿优化。 0、省流版本 如果采…

ip与mac-数据包传输过程学习

你管这破玩意叫网络&#xff1f; 内容来源于飞天闪客&#xff0c;以前没有学习过网络的相关基础知识&#xff0c;只会去瞎设置&#xff0c;现在终于是弄明白了。 多台电脑之间想要通信&#xff0c;可以直接通过一条网线进行连接。但是随着网线的增加&#xff0c;这个就会比较…

数值分析知识重构

数值分析知识重构 一 Question 请构造一下数值分析中的误差概念以及每一个具体数值方法的误差是如何估计的&#xff1f; 二 Question 已知 n 1 n1 n1个数据点 ( x i , y i ) , i 0 , 1 , ⋯ , n (x_i,y_i),i0,1,\cdots,n (xi​,yi​),i0,1,⋯,n,请使用多种方法建立数据之间…

使用 Qt QGraphicsView/QGraphicsScene 绘制色轮

使用 Qt QGraphicsView/QGraphicsScene 绘制色轮 本文介绍如何在 Qt 中利用 QGraphicsView 和 QGraphicsScene 实现基础圆形绘制&#xff0c;以及进阶的色轮&#xff08;Color Wheel&#xff09;效果。 色轮是色彩选择器的常见控件&#xff0c;广泛应用于图形设计、绘画和 UI …

移除链表元素数据结构oj题(力扣题206)

目录 题目描述&#xff1a; 题目解读&#xff08;分析&#xff09; 解决代码 题目描述&#xff1a; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 题目解读&#xff08;分析&#…

GLPK(GNU线性规划工具包)中建模语言MathProg的使用

GNU MathProg是一种用于描述线性数学规划模型的建模语言。用GNU MathProg语言编写的模型描述由一组语句和数据块组成。 在MathProg中&#xff0c;模型以集合、参数、变量、约束和目标(sets, parameters, variables, constraints, objectives称为模型对象)的形式进行描述。 在Ma…

《Python星球日记》 第77天:模型部署与总结

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、模型部署技术1. 模型文件导出不同模型格式对比2. 使用Flask构建RESTful API3. 使用FastAPI构建高性能API4. 部署优化与最佳实践二、部署架构…

【JavaWeb】MySQL(准备篇)

1 MySQL安装 1.1 解压 下载完成后我们得到的是一个压缩包&#xff08;所有文件均在文末安装包中&#xff09;&#xff0c;将其解压&#xff0c;我们就可以得到MySQL 8.0.34 的软件本体了(就是一个文件夹)&#xff0c;我们可以把它放在你想安装的位置 。 1.2 配置 1.2.1 配置…

国产数据库工具突围:SQLynx如何解决Navicat的三大痛点?深度体验报告

引言&#xff1a;Navicat的"中国困境" 当开发者面对达梦数据库的存储过程调试&#xff0c;或是在人大金仓中处理复杂查询时&#xff0c;Navicat突然变得力不从心——这不是个例。 真实痛点&#xff1a;某政务系统迁移至OceanBase后&#xff0c;开发团队发现Navicat无…

ETL数据集成产品选型需要关注哪些方面?

ETL&#xff08;Extract&#xff0c;Transform&#xff0c;Load&#xff09;工具作为数据仓库和数据分析流程中的关键环节&#xff0c;其选型对于企业的数据战略实施有着深远的影响。谷云科技在 ETL 领域耕耘多年&#xff0c;通过自身产品的实践应用&#xff0c;对 ETL 产品选型…

数据结构实验10.1:内部排序的基本运算

文章目录 一&#xff0c;实验目的二&#xff0c;实验内容1. 数据生成与初始化2. 排序算法实现&#xff08;1&#xff09;直接插入排序&#xff08;2&#xff09;二分插入排序&#xff08;3&#xff09;希尔排序&#xff08;4&#xff09;冒泡排序&#xff08;5&#xff09;快速…

从秒开到丝滑体验!WebAssembly助力ZKmall商城重构 B2B2C 商城性能基线

在 B2B2C 电商领域&#xff0c;用户对页面加载速度与交互流畅度的要求日益严苛。传统 Web 技术在处理复杂业务逻辑、海量数据渲染时&#xff0c;常出现卡顿、延迟等问题&#xff0c;导致用户流失。ZKmall 商城创新性地引入 WebAssembly&#xff08;简称 Wasm&#xff09;技术&a…

FD+Mysql的Insert时的字段赋值乱码问题

方法一 FDQuery4.SQL.Text : INSERT INTO 信息表 (中心, 分组) values(:中心,:分组); FDQuery4.Params[0].DataType : ftWideString; //必须加这个数据类型的定义&#xff0c;否则会有乱码 FDQuery4.Params[1].DataType : ftWideString; //ftstring就不行&#xff0c;必须是…

vue2.0 组件生命周期

个人简介 &#x1f468;‍&#x1f4bb;‍个人主页&#xff1a; 魔术师 &#x1f4d6;学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全栈发展 &#x1f6b4;个人状态&#xff1a; 研发工程师&#xff0c;现效力于政务服务网事业 &#x1f1e8;&#x1f1f3;人生格言&…

使用GmSSL v3.1.1实现SM2证书认证

1、首先使用gmssl命令生成根证书、客户端公私钥&#xff0c;然后使用根证书签发客户端证书&#xff1b; 2、然后编写代码完成认证功能&#xff0c;使用根证书验证客户端证书是否由自己签发&#xff0c;然后使用客户端证书验证客户端私钥对随机数的签名是否正确。 第一部分生成根…

升级mysql (rpm安装)

#备份以防万一 备份配置文件: /etc/my.cnf.d/server.cnf 备份数据: mysqldump -u your_username -p --all-databases > all_databases.sql #停止 systemctl stop mysql #卸载旧版 yum remove mariadb #安装新版( 通过yum安装报错,死活安装不了,只能rpm安装) 下载地址…

深入理解pip:Python包管理的核心工具与实战指南

# 深入理解pip&#xff1a;Python包管理的核心工具与实战指南 在Python开发中&#xff0c;第三方库是提升效率的关键。而pip作为Python官方的包管理工具&#xff0c;承担着安装、卸载、升级和管理库的重要职责。本文将全面解析pip的核心命令&#xff0c;结合实例演示用法&#…

Linux配置SSH密钥认证

介绍 配置SS秘钥认证后&#xff0c;可以通过shell脚本免密删除文件或执行命令。 # 生成密钥对&#xff08;如果还没有&#xff09; ssh-keygen -t rsa# 将公钥复制到服务器 ssh-copy-id "$remote_user$remote_host"

python打卡第30天

知识点回顾&#xff1a; 一&#xff0c;导入官方库的三种手段。 使用 import 直接导入整个模块 import module_name 使用 from ... import ... 导入特定功能 from module_name import function_name 使用 as 关键字重命名模块或功能 import module_name as alias # 或 from mod…