From d6fa969d1f4091e25d65c73618678e0c9283af91 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 22:25:40 +0800 Subject: [PATCH 1/9] add --- apps/server/src/models/term/term.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/server/src/models/term/term.service.ts b/apps/server/src/models/term/term.service.ts index 676d45e..7cbcc5f 100755 --- a/apps/server/src/models/term/term.service.ts +++ b/apps/server/src/models/term/term.service.ts @@ -352,7 +352,9 @@ export class TermService extends BaseTreeService { staff: UserProfile, data: z.infer, ) { - const { domainId = null, permissions } = staff; + // const { domainId = null, permissions } = staff; + const permissions = staff?.permissions || []; + const domainId = staff?.domainId || null; const hasAnyPerms = permissions.includes(RolePerms.READ_ANY_TERM) || permissions.includes(RolePerms.MANAGE_ANY_TERM); From 76ef17163c9733cd6163ad8f828455b68dad11c2 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 22:31:42 +0800 Subject: [PATCH 2/9] add --- apps/web/src/components/models/term/term-select.tsx | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/apps/web/src/components/models/term/term-select.tsx b/apps/web/src/components/models/term/term-select.tsx index 8f76f07..3896d8e 100755 --- a/apps/web/src/components/models/term/term-select.tsx +++ b/apps/web/src/components/models/term/term-select.tsx @@ -15,11 +15,9 @@ interface TermSelectProps { defaultValue?: string | string[]; value?: string | string[]; onChange?: (value: string | string[]) => void; - placeholder?: string; multiple?: boolean; taxonomyId?: string; disabled?: boolean; - className?: string; domainId?: string; dropdownStyle?: React.CSSProperties; style?: React.CSSProperties; @@ -34,7 +32,6 @@ export default function TermSelect({ defaultValue, value, onChange, - className, placeholder = "选择分类", multiple = false, taxonomyId, @@ -45,7 +42,8 @@ export default function TermSelect({ style, disabled = false, dropdownRender, -}: TermSelectProps) { + ...treeSelectProps +}: TermSelectProps & TreeSelectProps) { const utils = api.useUtils(); const [listTreeData, setListTreeData] = useState< Omit[] @@ -179,9 +177,6 @@ export default function TermSelect({ handleChange(multiple ? [] : undefined)} onTreeExpand={handleExpand} onDropdownVisibleChange={handleDropdownVisibleChange} + {...treeSelectProps} /> ); } From 1ed74e659011b2371d226ba8da291388315de7e0 Mon Sep 17 00:00:00 2001 From: Li1304553726 <1304553726@qq.com> Date: Tue, 25 Feb 2025 22:46:17 +0800 Subject: [PATCH 3/9] li . --- .../app/main/courses/components/CourseCard.tsx | 13 ++++++++----- .../src/app/main/layout/UserMenu/UserMenu.tsx | 16 +++++++--------- .../layout/element/usermenu/usermenu.tsx | 14 ++++++-------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/apps/web/src/app/main/courses/components/CourseCard.tsx b/apps/web/src/app/main/courses/components/CourseCard.tsx index 45dc274..963c691 100755 --- a/apps/web/src/app/main/courses/components/CourseCard.tsx +++ b/apps/web/src/app/main/courses/components/CourseCard.tsx @@ -46,10 +46,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" } @@ -87,12 +87,15 @@ export default function CourseCard({ course }: CourseCardProps) {
- {course?.depts?.map((depts) => depts.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})} */}
- 观看次数{course?.meta?.views}次 + {course?.meta?.views ? `观看次数 ${course?.meta?.views}` : null} diff --git a/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx b/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx index 508fdaa..ea23902 100755 --- a/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx +++ b/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx @@ -221,21 +221,19 @@ export function UserMenu() { focus:outline-none focus:ring-2 focus:ring-[#00538E]/20 group relative overflow-hidden - active:scale-[0.99] - ${ - item.label === "注销" + active:scale-[0.99] + ${item.label === "注销" ? "text-[#B22234] hover:bg-red-50/80 hover:text-red-700" : "text-[#00538E] hover:bg-[#E6EEF5] hover:text-[#003F6A]" - }`}> + }`}> + group-hover:translate-x-0.5 ${item.label === "注销" + ? "group-hover:text-red-600" + : "group-hover:text-[#003F6A]" + }`}> {item.icon} {item.label} diff --git a/apps/web/src/components/layout/element/usermenu/usermenu.tsx b/apps/web/src/components/layout/element/usermenu/usermenu.tsx index d2611dd..31460cd 100755 --- a/apps/web/src/components/layout/element/usermenu/usermenu.tsx +++ b/apps/web/src/components/layout/element/usermenu/usermenu.tsx @@ -229,20 +229,18 @@ export function UserMenu() { focus:ring-2 focus:ring-[#00538E]/20 group relative overflow-hidden active:scale-[0.99] - ${ - item.label === "注销" + ${item.label === "注销" ? "text-[#B22234] hover:bg-red-50/80 hover:text-red-700" : "text-[#00538E] hover:bg-[#E6EEF5] hover:text-[#003F6A]" - }`}> + }`}> + group-hover:translate-x-0.5 ${item.label === "注销" + ? "group-hover:text-red-600" + : "group-hover:text-[#003F6A]" + }`}> {item.icon} {item.label} From c09b3ea0cf2d091bf7ae93fdb4f829eb7a43142b Mon Sep 17 00:00:00 2001 From: wfc <2146706290@qq.com> Date: Wed, 26 Feb 2025 08:50:18 +0800 Subject: [PATCH 4/9] m --- apps/web/src/app/admin/base-setting/page.tsx | 8 +- .../common/uploader/AvatarUploader.tsx | 12 +- .../common/uploader/MultiAvatarUploader.tsx | 68 +++++++ .../common/uploader/MultiImageUploader.tsx | 173 ------------------ .../common/uploader/TestUploader.tsx | 18 -- 5 files changed, 80 insertions(+), 199 deletions(-) create mode 100644 apps/web/src/components/common/uploader/MultiAvatarUploader.tsx delete mode 100644 apps/web/src/components/common/uploader/MultiImageUploader.tsx delete mode 100644 apps/web/src/components/common/uploader/TestUploader.tsx diff --git a/apps/web/src/app/admin/base-setting/page.tsx b/apps/web/src/app/admin/base-setting/page.tsx index c0aed70..aaed815 100755 --- a/apps/web/src/app/admin/base-setting/page.tsx +++ b/apps/web/src/app/admin/base-setting/page.tsx @@ -3,7 +3,7 @@ import { useContext, useEffect, useState } from "react"; import { Button, Form, Input, message, theme } from "antd"; import { useAppConfig } from "@nice/client"; import { useAuth } from "@web/src/providers/auth-provider"; -import MultiImageUploader from "@web/src/components/common/uploader/MultiImageUploader"; +import MultiAvatarUploader from "@web/src/components/common/uploader/MultiAvatarUploader"; import FixedHeader from "@web/src/components/layout/fix-header"; import { useForm } from "antd/es/form/Form"; @@ -129,9 +129,9 @@ export default function BaseSettingPage() {
- +
{/*
+ ghost> 清除行模型缓存
diff --git a/apps/web/src/components/common/uploader/AvatarUploader.tsx b/apps/web/src/components/common/uploader/AvatarUploader.tsx index abbb355..33246c8 100755 --- a/apps/web/src/components/common/uploader/AvatarUploader.tsx +++ b/apps/web/src/components/common/uploader/AvatarUploader.tsx @@ -12,6 +12,8 @@ export interface AvatarUploaderProps { onChange?: (value: string) => void; compressed?: boolean; style?: React.CSSProperties; // 添加style属性 + successText?: string; + showCover?: boolean; } interface UploadingFile { @@ -31,6 +33,8 @@ const AvatarUploader: React.FC = ({ className, placeholder = "点击上传", style, // 解构style属性 + successText = "上传成功", + showCover = true, }) => { const { handleFileUpload, uploadProgress } = useTusUpload(); const [file, setFile] = useState(null); @@ -92,12 +96,12 @@ const AvatarUploader: React.FC = ({ // 使用 resolved 的最新值调用 onChange // 强制刷新 Avatar 组件 setAvatarKey((prev) => prev + 1); // 修改 key 强制重新挂载 - onChange?.(uploadedUrl); console.log(uploadedUrl); - toast.success("头像上传成功"); + onChange?.(uploadedUrl); + toast.success(successText); } catch (error) { console.error("上传错误:", error); - toast.error("头像上传失败"); + toast.error("上传失败"); setFile((prev) => ({ ...prev!, status: "error" })); } finally { setUploading(false); @@ -124,7 +128,7 @@ const AvatarUploader: React.FC = ({ accept="image/*" style={{ display: "none" }} /> - {previewUrl ? ( + {(previewUrl && showCover) ? ( void; +} + +export function MultiAvatarUploader({ + value, + onChange, +}: MultiAvatarUploaderProps) { + const [imageList, setImageList] = useState(value || []) + const [previewImage, setPreviewImage] = useState(""); + useEffect(() => { + if (!isEqual(value, imageList)) { + setImageList(value || []); + } + }, [value]); + useEffect(() => { + onChange?.(imageList) + }, [imageList]) + return <> +
+ {imageList.map((image, index) => { + return ( +
+ + setPreviewImage(visible ? image || "" : "") + }} > + +
+ ) + })} +
+
+ { + console.log(value); + setImageList([...imageList, value]) + }}> +
+ + ; +} +export default MultiAvatarUploader; \ No newline at end of file diff --git a/apps/web/src/components/common/uploader/MultiImageUploader.tsx b/apps/web/src/components/common/uploader/MultiImageUploader.tsx deleted file mode 100644 index 5f6d026..0000000 --- a/apps/web/src/components/common/uploader/MultiImageUploader.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React, { useState } from 'react'; -import { Upload, Modal, message } from 'antd'; -import { PlusOutlined } from '@ant-design/icons'; -import { useTusUpload } from "@web/src/hooks/useTusUpload"; -import toast from "react-hot-toast"; - - -export interface MultiImageUploadProps { - value?: string; - placeholder?: string; - className?: string; - onChange?: (value: string) => void; - compressed?: boolean; - style?: React.CSSProperties; // 添加style属性 -} - -interface UploadFile { - name: string; - progress: number; - status: "uploading" | "done" | "error"; - url?: string; - fileKey?: string; - uid: string; -} -const MultiImageUpload: React.FC = ({ - value, - onChange, - compressed = false, - className, - placeholder = "点击上传", - style, // 解构style属性 -}) => { - const [fileList, setFileList] = useState(null); // 存储已上传的文件列表 - const [previewVisible, setPreviewVisible] = useState(false); // 控制预览模态框的显示 - const [previewImage, setPreviewImage] = useState(''); // 当前预览的图片URL - const { handleFileUpload, uploadProgress } = useTusUpload(); - const [compressedUrl, setCompressedUrl] = useState(value || ""); - const [url, setUrl] = useState(value || ""); - const [uploading, setUploading] = useState(false); - - // 处理文件上传前的校验 - const beforeUpload = (file) => { - const isImage = file.type.startsWith('image/'); - if (!isImage) { - message.error('只能上传图片文件!'); - } - const isLt10M = file.size / 1024 / 1024 < 10; - if (!isLt10M) { - message.error('图片大小不能超过10MB!'); - } - return isImage && isLt10M; - }; - - // 处理文件列表变化 - const handleChange = async ({ fileList }) => { - //setFileList(fileList); - console.log(fileList); - const imageUrls = fileList.map(file => { - return URL.createObjectURL(file.originFileObj) - }); - console.log("imageUrls", imageUrls); - - const newFileList = fileList.map(file => { - return { - name: file.name, - progress: 0, - status: "uploading", - //uid: file.uid, - fileKey: `${file.name}-${Date.now()}`, - //url: file.url, - } - }); - console.log("newFileList", newFileList); - setUploading(true); - - try { - const resFileList = newFileList.map(async (file, index) => { - const uploadedUrl = await new Promise((resolve, reject) => { - handleFileUpload( - fileList[index].originFileObj, - (result) => { - () => { - return { - ...newFileList[index], - progress: 100, - status: "done", - fileId: result.fileId, - url: result.url, - compressedUrl: result.compressedUrl, - } - } - // setFile((prev) => ({ - // ...prev!, - // progress: 100, - // status: "done", - // fileId: result.fileId, - // url: result.url, - // compressedUrl: result.compressedUrl, - // })); - setUrl(result.url); - setCompressedUrl(result.compressedUrl); - // 直接使用 result 中的最新值 - resolve(compressed ? result.compressedUrl : result.url); - }, - (error) => { - reject(error); - }, - newFileList[index]?.fileKey - ); - }); - }) - // await new Promise((resolve) => setTimeout(resolve,4999)); // 方法1:使用 await 暂停执行 - // 使用 resolved 的最新值调用 onChange - // 强制刷新 Avatar 组件 - // setAvatarKey((prev) => prev + 1); // 修改 key 强制重新挂载 - onChange?.(resFileList); - console.log(resFileList); - toast.success("图片上传成功"); - } catch (error) { - console.error("上传错误:", error); - toast.error("图片上传失败"); - // setFile((prev) => ({ ...prev!, status: "error" })); - } finally { - setUploading(false); - } - };uploadProgress - - // 处理预览 - const handlePreview = async (file) => { - if (!file.url && !file.preview) { - file.preview = await getBase64(file.originFileObj); - } - setPreviewImage(file.url || file.preview); - setPreviewVisible(true); - }; - - // 关闭预览模态框 - const handleCancel = () => setPreviewVisible(false); - - // 将文件转换为Base64格式(用于预览) - const getBase64 = (file) => { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => resolve(reader.result); - reader.onerror = (error) => reject(error); - }); - }; - - return ( -
- -

-

-

点击或拖拽文件到此区域上传

-

支持单个或批量上传

-
- - 预览 - -
- ); -}; - -export default MultiImageUpload; diff --git a/apps/web/src/components/common/uploader/TestUploader.tsx b/apps/web/src/components/common/uploader/TestUploader.tsx deleted file mode 100644 index d4c196e..0000000 --- a/apps/web/src/components/common/uploader/TestUploader.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import AvatarUploader from "./AvatarUploader" - - - -interface TestUploaderProps { - value?: string[], - onChange?: (value: string[]) => void -} - -export function TestUploader({ - value, - onChange, -}: TestUploaderProps) { - - return <> - - -} \ No newline at end of file From c7748946e47e44071949c5db3f726bbe500937c4 Mon Sep 17 00:00:00 2001 From: Li1304553726 <1304553726@qq.com> Date: Wed, 26 Feb 2025 08:57:41 +0800 Subject: [PATCH 5/9] add . --- apps/web/src/app/main/home/components/HeroSection.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/main/home/components/HeroSection.tsx b/apps/web/src/app/main/home/components/HeroSection.tsx index 10ecbfe..404ea27 100755 --- a/apps/web/src/app/main/home/components/HeroSection.tsx +++ b/apps/web/src/app/main/home/components/HeroSection.tsx @@ -63,9 +63,8 @@ const HeroSection = () => { }, []); const { slides } = useAppConfig() useEffect(() => { - //slides.push(('https://s.cn.bing.net/th?id=OHR.GiantCuttlefish_ZH-CN0670915878_1920x1080.webp&qlt=50')) - //console.log(slides) - }, []) + console.log(statistics) + }, [statistics]) return (
From c1c57612e124df13707251fb5c01addfc5010bf6 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Wed, 26 Feb 2025 09:01:09 +0800 Subject: [PATCH 6/9] add --- .../main/courses/components/CourseCard.tsx | 16 +- .../main/home/components/CoursesSection.tsx | 1 + .../editor/context/CourseEditorContext.tsx | 5 + .../course/editor/form/CourseBasicForm.tsx | 4 + .../models/course/list/CourseList.tsx | 3 + .../components/models/term/term-select.tsx | 2 +- .../src/components/models/term/term-tree.tsx | 199 ------------------ 7 files changed, 24 insertions(+), 206 deletions(-) delete mode 100644 apps/web/src/components/models/term/term-tree.tsx diff --git a/apps/web/src/app/main/courses/components/CourseCard.tsx b/apps/web/src/app/main/courses/components/CourseCard.tsx index 963c691..4914662 100755 --- a/apps/web/src/app/main/courses/components/CourseCard.tsx +++ b/apps/web/src/app/main/courses/components/CourseCard.tsx @@ -33,6 +33,7 @@ export default function CourseCard({ course }: CourseCardProps) { backgroundImage: `url(${course?.meta?.thumbnail})`, }} /> +
@@ -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} */}
+ @@ -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> diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index aa2bf07..9f45863 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -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} + diff --git a/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx b/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx index 6a12e2c..6b61854 100755 --- a/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx +++ b/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx @@ -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), diff --git a/apps/web/src/components/models/course/editor/form/CourseBasicForm.tsx b/apps/web/src/components/models/course/editor/form/CourseBasicForm.tsx index b05579b..cf683f1 100755 --- a/apps/web/src/components/models/course/editor/form/CourseBasicForm.tsx +++ b/apps/web/src/components/models/course/editor/form/CourseBasicForm.tsx @@ -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 }} /> + + + {taxonomies && taxonomies.map((tax, index) => ( ; + } return (
{courses.length > 0 ? ( diff --git a/apps/web/src/components/models/term/term-select.tsx b/apps/web/src/components/models/term/term-select.tsx index 3896d8e..95990dd 100755 --- a/apps/web/src/components/models/term/term-select.tsx +++ b/apps/web/src/components/models/term/term-select.tsx @@ -48,7 +48,7 @@ export default function TermSelect({ const [listTreeData, setListTreeData] = useState< Omit[] >([]); - + const fetchParentTerms = useCallback( async (termIds: string | string[], taxonomyId?: string) => { const idsArray = Array.isArray(termIds) diff --git a/apps/web/src/components/models/term/term-tree.tsx b/apps/web/src/components/models/term/term-tree.tsx deleted file mode 100644 index ae88a68..0000000 --- a/apps/web/src/components/models/term/term-tree.tsx +++ /dev/null @@ -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 = ({ - defaultValue, - value, - onChange, - className, - multiple = false, - taxonomyId, - domainId, - disabled = false, - style, -}) => { - const utils = api.useUtils(); - const [treeData, setTreeData] = useState([]); - - 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 ( - - ); -}; - -export default TermTree; From cf8c2e31f81d154f8936a57221782f7b9ede91a4 Mon Sep 17 00:00:00 2001 From: wfc <2146706290@qq.com> Date: Wed, 26 Feb 2025 09:01:34 +0800 Subject: [PATCH 7/9] upate --- apps/web/src/app/admin/base-setting/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/app/admin/base-setting/page.tsx b/apps/web/src/app/admin/base-setting/page.tsx index aaed815..b4a6b0b 100755 --- a/apps/web/src/app/admin/base-setting/page.tsx +++ b/apps/web/src/app/admin/base-setting/page.tsx @@ -40,7 +40,7 @@ export default function BaseSettingPage() { form.setFieldsValue(baseSetting); } setIsFormChanged(false); - } + } function onSaveClick() { if (form) form.submit(); } From 8bf670074d4493663c3758dcc4d7f51d7a3ef69a Mon Sep 17 00:00:00 2001 From: ditiqi Date: Wed, 26 Feb 2025 09:02:20 +0800 Subject: [PATCH 8/9] ff --- apps/web/src/app/main/courses/components/FilterSection.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx index 203e1d1..8b7471a 100755 --- a/apps/web/src/app/main/courses/components/FilterSection.tsx +++ b/apps/web/src/app/main/courses/components/FilterSection.tsx @@ -28,6 +28,7 @@ export default function FilterSection() {

{tax?.name}

+ Date: Wed, 26 Feb 2025 09:09:52 +0800 Subject: [PATCH 9/9] add --- apps/web/src/app/admin/base-setting/page.tsx | 4 +- .../app/main/home/components/HeroSection.tsx | 34 +++-- .../common/uploader/MultiAvatarUploader.tsx | 127 ++++++++++-------- 3 files changed, 98 insertions(+), 67 deletions(-) diff --git a/apps/web/src/app/admin/base-setting/page.tsx b/apps/web/src/app/admin/base-setting/page.tsx index b4a6b0b..d4a4efa 100755 --- a/apps/web/src/app/admin/base-setting/page.tsx +++ b/apps/web/src/app/admin/base-setting/page.tsx @@ -40,7 +40,7 @@ export default function BaseSettingPage() { form.setFieldsValue(baseSetting); } setIsFormChanged(false); - } + } function onSaveClick() { if (form) form.submit(); } @@ -56,7 +56,7 @@ export default function BaseSettingPage() { meta: { ...baseSetting, appConfig: { - ...baseSetting.appConfig, + ...(baseSetting?.appConfig || {}), ...appConfig, }, }, diff --git a/apps/web/src/app/main/home/components/HeroSection.tsx b/apps/web/src/app/main/home/components/HeroSection.tsx index 404ea27..c20ada6 100755 --- a/apps/web/src/app/main/home/components/HeroSection.tsx +++ b/apps/web/src/app/main/home/components/HeroSection.tsx @@ -49,10 +49,26 @@ const HeroSection = () => { const carouselRef = useRef(null); const { statistics, baseSetting } = useAppConfig(); const platformStats: PlatformStat[] = [ - { icon: , value: statistics.staffs.toString(), label: "注册学员" }, - { icon: , value: statistics.courses.toString(), label: "精品课程" }, - { icon: , value: statistics.lectures.toString(), label: '课程章节' }, - { icon: , value: statistics.reads.toString(), label: "观看次数" }, + { + icon: , + value: statistics.staffs.toString(), + label: "注册学员", + }, + { + icon: , + value: statistics.courses.toString(), + label: "精品课程", + }, + { + icon: , + value: statistics.lectures.toString(), + label: "课程章节", + }, + { + icon: , + value: statistics.reads.toString(), + label: "观看次数", + }, ]; const handlePrev = useCallback(() => { carouselRef.current?.prev(); @@ -61,10 +77,10 @@ const HeroSection = () => { const handleNext = useCallback(() => { carouselRef.current?.next(); }, []); - const { slides } = useAppConfig() + const { slides } = useAppConfig(); useEffect(() => { - console.log(statistics) - }, [statistics]) + console.log(statistics); + }, [statistics]); return (
@@ -76,8 +92,8 @@ const HeroSection = () => { dots={{ className: "carousel-dots !bottom-32 !z-20", }}> - {Array.isArray(slides)? - (slides.map((item, index) => ( + {Array.isArray(slides) ? ( + slides.map((item, index) => (
void; + value?: string[]; + onChange?: (value: string[]) => void; } export function MultiAvatarUploader({ - value, - onChange, + value, + onChange, }: MultiAvatarUploaderProps) { - const [imageList, setImageList] = useState(value || []) - const [previewImage, setPreviewImage] = useState(""); - useEffect(() => { - if (!isEqual(value, imageList)) { - setImageList(value || []); - } - }, [value]); - useEffect(() => { - onChange?.(imageList) - }, [imageList]) - return <> -
- {imageList.map((image, index) => { - return ( -
- - setPreviewImage(visible ? image || "" : "") - }} > - -
- ) - })} -
-
- { - console.log(value); - setImageList([...imageList, value]) - }}> -
- - ; + const [imageList, setImageList] = useState(value || []); + const [previewImage, setPreviewImage] = useState(""); + useEffect(() => { + if (!isEqual(value, imageList)) { + setImageList(value || []); + } + }, [value]); + useEffect(() => { + onChange?.(imageList); + }, [imageList]); + return ( + <> +
+ {(imageList || [])?.map((image, index) => { + return ( +
+ + setPreviewImage( + visible ? image || "" : "" + ), + }}> +
+ ); + })} +
+
+ { + console.log(value); + setImageList([...imageList, value]); + }}> +
+ + ); } -export default MultiAvatarUploader; \ No newline at end of file +export default MultiAvatarUploader;