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.pswp.cn/pingmian/81584.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/81584.shtml
英文地址,請注明出處:http://en.pswp.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…