This commit is contained in:
ditiqi 2025-02-26 09:01:09 +08:00
parent 6805aba768
commit c1c57612e1
7 changed files with 24 additions and 206 deletions

View File

@ -33,6 +33,7 @@ export default function CourseCard({ course }: CourseCardProps) {
backgroundImage: `url(${course?.meta?.thumbnail})`,
}}
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-80 group-hover:opacity-60 transition-opacity duration-300" />
<PlayCircleOutlined className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-6xl text-white/90 opacity-0 group-hover:opacity-100 transition-all duration-300" />
</div>
@ -46,10 +47,10 @@ export default function CourseCard({ course }: CourseCardProps) {
// color={term.taxonomy.slug===TaxonomySlug.CATEGORY? "blue" : "green"}
color={
term?.taxonomy?.slug ===
TaxonomySlug.CATEGORY
TaxonomySlug.CATEGORY
? "blue"
: term?.taxonomy?.slug ===
TaxonomySlug.LEVEL
TaxonomySlug.LEVEL
? "green"
: "orange"
}
@ -77,6 +78,7 @@ export default function CourseCard({ course }: CourseCardProps) {
{course.terms?.[1].name}
</Tag> */}
</div>
<Title
level={4}
className="mb-4 line-clamp-2 font-bold leading-snug text-gray-800 hover:text-blue-600 transition-colors duration-300 group-hover:scale-[1.02] transform origin-left">
@ -87,15 +89,17 @@ export default function CourseCard({ course }: CourseCardProps) {
<TeamOutlined className="text-blue-500 text-lg transform group-hover:scale-110 transition-transform duration-300" />
<div className="ml-2 flex items-center flex-grow">
<Text className="font-medium text-blue-500 hover:text-blue-600 transition-colors duration-300 truncate max-w-[120px]">
{
course?.depts.length > 1 ?`${course.depts[0].name}`:course.depts[0].name
}
{course?.depts?.length > 1
? `${course.depts[0].name}`
: course?.depts?.[0]?.name}
{/* {course?.depts?.map((dept) => {return dept.name.length > 1 ?`${dept.name.slice}等`: dept.name})} */}
{/* {course?.depts?.map((dept)=>{return dept.name})} */}
</Text>
</div>
<span className="text-xs font-medium text-gray-500">
{course?.meta?.views ? `观看次数 ${course?.meta?.views}` : null}
{course?.meta?.views
? `观看次数 ${course?.meta?.views}`
: null}
</span>
</div>

View File

@ -52,6 +52,7 @@ const CoursesSection: React.FC<CoursesSectionProps> = ({
className="font-bold text-5xl mb-6 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
{title}
</Title>
<Text
type="secondary"
className="text-xl font-light text-gray-600">

View File

@ -83,6 +83,7 @@ export function CourseFormProvider({
const onSubmit = async (values: any) => {
console.log(values);
const sections = values?.sections || [];
const deptIds = values?.deptIds || [];
const termIds = taxonomies
.map((tax) => values[tax.id]) // 获取每个 taxonomy 对应的选中值
.filter((id) => id); // 过滤掉空值
@ -95,12 +96,16 @@ export function CourseFormProvider({
terms: {
connect: termIds.map((id) => ({ id })), // 转换成 connect 格式
},
depts: {
connect: deptIds.map((id) => ({ id })),
},
};
// 删除原始的 taxonomy 字段
taxonomies.forEach((tax) => {
delete formattedValues[tax.id];
});
delete formattedValues.sections;
delete formattedValues.deptIds;
if (course) {
formattedValues.meta = {
...(course?.meta as CourseMeta),

View File

@ -4,6 +4,7 @@ import { convertToOptions } from "@nice/client";
import TermSelect from "../../../term/term-select";
import { useCourseEditor } from "../context/CourseEditorContext";
import AvatarUploader from "@web/src/components/common/uploader/AvatarUploader";
import DepartmentSelect from "../../../department/department-select";
const { TextArea } = Input;
@ -48,6 +49,9 @@ export function CourseBasicForm() {
autoSize={{ minRows: 3, maxRows: 6 }}
/>
</Form.Item>
<Form.Item name="deptIds" label="参与单位">
<DepartmentSelect multiple />
</Form.Item>
{taxonomies &&
taxonomies.map((tax, index) => (
<Form.Item

View File

@ -54,6 +54,9 @@ export default function CourseList({
setCurrentPage(page);
window.scrollTo({ top: 0, behavior: "smooth" });
}
if (isLoading) {
return <Skeleton paragraph={{ rows: 10 }}></Skeleton>;
}
return (
<div className="space-y-6">
{courses.length > 0 ? (

View File

@ -48,7 +48,7 @@ export default function TermSelect({
const [listTreeData, setListTreeData] = useState<
Omit<DefaultOptionType, "label">[]
>([]);
const fetchParentTerms = useCallback(
async (termIds: string | string[], taxonomyId?: string) => {
const idsArray = Array.isArray(termIds)

View File

@ -1,199 +0,0 @@
import React, { useEffect, useState, useCallback } from "react";
import { Tree } from "antd";
import type { DataNode, TreeProps } from "antd/es/tree";
import { getUniqueItems } from "@nice/common";
import { api } from "@nice/client";
interface TermData {
value?: string;
children?: TermData[];
key?: string;
hasChildren?: boolean;
isLeaf?: boolean;
pId?: string;
title?: React.ReactNode;
data?: any;
order?: string;
id?: string;
}
interface TermTreeProps {
defaultValue?: string | string[];
value?: string | string[];
onChange?: (value: string | string[]) => void;
multiple?: boolean;
taxonomyId?: string;
disabled?: boolean;
className?: string;
domainId?: string;
style?: React.CSSProperties;
}
const TermTree: React.FC<TermTreeProps> = ({
defaultValue,
value,
onChange,
className,
multiple = false,
taxonomyId,
domainId,
disabled = false,
style,
}) => {
const utils = api.useUtils();
const [treeData, setTreeData] = useState<TermData[]>([]);
const processTermData = (terms: TermData[]): TermData[] => {
return terms.map((term) => ({
...term,
key: term.key || term.id || "",
title: term.title || term.value,
children: term.children
? processTermData(term.children)
: undefined,
}));
};
const fetchParentTerms = useCallback(
async (termIds: string | string[], taxonomyId?: string) => {
const idsArray = Array.isArray(termIds)
? termIds
: [termIds].filter(Boolean);
try {
const result = await utils.term.getParentSimpleTree.fetch({
termIds: idsArray,
taxonomyId,
domainId,
});
return processTermData(result);
} catch (error) {
console.error(
"Error fetching parent terms for termIds",
idsArray,
":",
error
);
throw error;
}
},
[utils, domainId]
);
const fetchTerms = useCallback(async () => {
try {
const rootTerms = await utils.term.getChildSimpleTree.fetch({
taxonomyId,
domainId,
});
let combinedTerms = processTermData(rootTerms);
if (defaultValue) {
const defaultTerms = await fetchParentTerms(
defaultValue,
taxonomyId
);
combinedTerms = getUniqueItems(
[...treeData, ...combinedTerms, ...defaultTerms],
"key"
);
}
if (value) {
const valueTerms = await fetchParentTerms(value, taxonomyId);
combinedTerms = getUniqueItems(
[...treeData, ...combinedTerms, ...valueTerms],
"key"
);
}
setTreeData(combinedTerms);
} catch (error) {
console.error("Error fetching terms:", error);
}
}, [
defaultValue,
value,
taxonomyId,
utils,
fetchParentTerms,
domainId,
treeData,
]);
useEffect(() => {
fetchTerms();
}, [fetchTerms]);
const onLoadData = async ({ key }: any) => {
try {
const result = await utils.term.getChildSimpleTree.fetch({
termIds: [key],
taxonomyId,
domainId,
});
const processedResult = processTermData(result);
const newItems = getUniqueItems(
[...treeData, ...processedResult],
"key"
);
setTreeData(newItems);
} catch (error) {
console.error(
"Error loading data for node with key",
key,
":",
error
);
}
};
const handleCheck: TreeProps["onCheck"] = (checkedKeys, info) => {
if (onChange) {
if (multiple) {
onChange(checkedKeys as string[]);
} else {
onChange((checkedKeys as string[])[0] || "");
}
}
};
const handleExpand = async (expandedKeys: React.Key[]) => {
try {
const allKeyIds = expandedKeys
.map((key) => key.toString())
.filter(Boolean);
const expandedNodes = await utils.term.getChildSimpleTree.fetch({
termIds: allKeyIds,
taxonomyId,
domainId,
});
const processedNodes = processTermData(expandedNodes);
const newItems = getUniqueItems(
[...treeData, ...processedNodes],
"key"
);
setTreeData(newItems);
} catch (error) {
console.error(
"Error expanding nodes with keys",
expandedKeys,
":",
error
);
}
};
return (
<Tree
checkable={multiple}
disabled={disabled}
className={className}
style={style}
treeData={treeData as DataNode[]}
checkedKeys={Array.isArray(value) ? value : value ? [value] : []}
onCheck={handleCheck}
loadData={onLoadData}
onExpand={handleExpand}
/>
);
};
export default TermTree;