diff --git a/.gitignore b/.gitignore index 2e6bac7..4954c82 100755 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ backup # dependencies **/node_modules/ volumes +web-dist /.pnp .pnp.js *.tar @@ -69,4 +70,4 @@ yarn-error.log* **/.idea/ uploads packages/mind-elixir-core -config/nginx/conf.d/web.conf \ No newline at end of file +config/nginx/conf.d/web.conf diff --git a/Dockerfile b/Dockerfile index 0a51235..3d15a41 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,51 +1,23 @@ # 基础镜像 FROM node:18.17-alpine as base -# 更改 apk 镜像源为阿里云 -# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories - -# 使用阿里云镜像源 + 完整仓库声明 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ echo "https://mirrors.aliyun.com/alpine/v3.18/community" >> /etc/apk/repositories -# 安装最新稳定版 PostgreSQL 客户端(15.11) -RUN apk update --no-cache && \ - apk add --no-cache \ - postgresql15-client \ - libpq \ - readline - - RUN apk add --no-cache ffmpeg - -# 设置 npm 镜像源 RUN yarn config set registry https://registry.npmmirror.com - -# 全局安装 pnpm 并设置其镜像源 RUN yarn global add pnpm && pnpm config set registry https://registry.npmmirror.com - -# 设置工作目录 WORKDIR /app - -# 复制 pnpm workspace 配置文件 COPY pnpm-workspace.yaml ./ - -# 首先复制 package.json, package-lock.json 和 pnpm-lock.yaml 文件 COPY package*.json pnpm-lock.yaml* ./ - COPY tsconfig.base.json . -# 利用 Docker 缓存机制,如果依赖没有改变则不会重新执行 pnpm install -#100-500 5-40 + FROM base As server-build WORKDIR /app -COPY packages/common /app/packages/common -COPY packages/tus /app/packages/tus -COPY apps/server /app/apps/server -RUN pnpm config set registry https://registry.npmmirror.com/ -RUN pnpm install --filter common -RUN pnpm install --filter tus -RUN pnpm install --filter server -RUN pnpm --filter common generate && pnpm --filter common build:cjs +COPY . . +RUN pnpm install +RUN pnpm --filter common build RUN pnpm --filter tus build +RUN pnpm --filter utils build RUN pnpm --filter server build FROM base As server-prod-dep @@ -55,6 +27,7 @@ COPY packages/tus /app/packages/tus COPY apps/server /app/apps/server RUN pnpm install --filter common --prod RUN pnpm install --filter tus --prod +RUN pnpm install --filter utils --prod RUN pnpm install --filter server --prod @@ -66,10 +39,8 @@ COPY --from=server-build /app/packages/common/dist ./packages/common/dist COPY --from=server-build /app/packages/tus/dist ./packages/tus/dist COPY --from=server-build /app/apps/server/dist ./apps/server/dist COPY apps/server/entrypoint.sh ./apps/server/entrypoint.sh - RUN chmod +x ./apps/server/entrypoint.sh -RUN apk add --no-cache postgresql-client - +RUN apk add --no-cache ffmpeg EXPOSE 3000 @@ -108,21 +79,15 @@ CMD ["/usr/bin/entrypoint.sh"] # 使用 Nginx 的 Alpine 版本作为基础镜像 FROM nginx:stable-alpine as nginx - # 替换 Alpine 的软件源为阿里云镜像 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories - # 设置工作目录 WORKDIR /usr/share/nginx/html - # 设置环境变量 ENV NODE_ENV production - # 安装 envsubst 和 inotify-tools RUN apk add --no-cache gettext inotify-tools - # 创建 /data/uploads 目录 RUN mkdir -p /data/uploads - # 暴露 80 端口 EXPOSE 80 \ No newline at end of file diff --git a/apps/server/src/queue/models/post/utils.ts b/apps/server/src/queue/models/post/utils.ts index 7e3c3f1..932d4b3 100755 --- a/apps/server/src/queue/models/post/utils.ts +++ b/apps/server/src/queue/models/post/utils.ts @@ -107,10 +107,10 @@ export async function updatePostViewCount(id: string, type: VisitType) { where: { id: course.id }, data: { [metaFieldMap[type]]: courseViews._sum.views || 0, - meta: { - ...((post?.meta as any) || {}), - [metaFieldMap[type]]: courseViews._sum.views || 0, - }, + // meta: { + // ...((post?.meta as any) || {}), + // [metaFieldMap[type]]: courseViews._sum.views || 0, + // }, }, }); } @@ -127,10 +127,10 @@ export async function updatePostViewCount(id: string, type: VisitType) { where: { id }, data: { [metaFieldMap[type]]: totalViews._sum.views || 0, - meta: { - ...((post?.meta as any) || {}), - [metaFieldMap[type]]: totalViews._sum.views || 0, - }, + // meta: { + // ...((post?.meta as any) || {}), + // [metaFieldMap[type]]: totalViews._sum.views || 0, + // }, }, }); } diff --git a/apps/server/src/tasks/init/init.service.ts b/apps/server/src/tasks/init/init.service.ts index 8d6a955..b4f94b1 100755 --- a/apps/server/src/tasks/init/init.service.ts +++ b/apps/server/src/tasks/init/init.service.ts @@ -41,12 +41,11 @@ export class InitService { const existingTaxonomies = await db.taxonomy.findMany(); const existingTaxonomyMap = new Map( - existingTaxonomies.map((taxonomy) => [taxonomy.name, taxonomy]), + existingTaxonomies.map((taxonomy) => [taxonomy.slug, taxonomy]), ); for (const [index, taxonomy] of InitTaxonomies.entries()) { - const existingTaxonomy = existingTaxonomyMap.get(taxonomy.name); - + const existingTaxonomy = existingTaxonomyMap.get(taxonomy.slug); if (!existingTaxonomy) { // Create new taxonomy await db.taxonomy.create({ @@ -56,12 +55,12 @@ export class InitService { }, }); this.logger.log(`Created new taxonomy: ${taxonomy.name}`); - } else { + } else if(process.env.NODE_ENV === 'development'){ // Check for differences and update if necessary const differences = Object.keys(taxonomy).filter( (key) => taxonomy[key] !== existingTaxonomy[key], ); - + if (differences.length > 0) { await db.taxonomy.update({ where: { id: existingTaxonomy.id }, diff --git a/apps/web/.env.example b/apps/web/.env.example index 4d30872..826fc8f 100755 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -1,4 +1,4 @@ -VITE_APP_SERVER_IP=192.168.252.239 +VITE_APP_SERVER_IP=localhost VITE_APP_SERVER_PORT=3000 VITE_APP_FILE_PORT=80 VITE_APP_VERSION=0.3.0 diff --git a/apps/web/index.html b/apps/web/index.html index 6199b0c..4af329b 100755 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -7,12 +7,14 @@ - fhmooc + $APP_NAME diff --git a/apps/web/package.json b/apps/web/package.json index 909aa90..b484901 100755 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -34,7 +34,6 @@ "@nice/common": "workspace:^", "@nice/config": "workspace:^", "@nice/iconer": "workspace:^", - "@nice/ui": "workspace:^", "@nice/utils": "workspace:^", "@tanstack/query-async-storage-persister": "^5.51.9", "@tanstack/react-query": "^5.51.21", diff --git a/apps/web/public/placeholder.webp b/apps/web/public/placeholder.webp old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/home/components/HeroSection.tsx b/apps/web/src/app/main/home/components/HeroSection.tsx index 74643fb..f4c21fd 100755 --- a/apps/web/src/app/main/home/components/HeroSection.tsx +++ b/apps/web/src/app/main/home/components/HeroSection.tsx @@ -18,16 +18,6 @@ import type { CarouselRef } from "antd/es/carousel"; import { useAppConfig } from "@nice/client"; import { useNavigate } from "react-router-dom"; -const { Title, Text } = Typography; - -interface CarouselItem { - title: string; - desc: string; - image: string; - action: string; - color: string; -} - interface PlatformStat { icon: React.ReactNode; value: number; diff --git a/apps/web/src/app/main/layout/BasePost/BasePostLayout.tsx b/apps/web/src/app/main/layout/BasePost/BasePostLayout.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/layout/BasePost/SearchModeRadio.tsx b/apps/web/src/app/main/layout/BasePost/SearchModeRadio.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/my-duty-path/components/MyDutyPathContainer.tsx b/apps/web/src/app/main/my-duty-path/components/MyDutyPathContainer.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/my-duty/components/MyDutyListContainer.tsx b/apps/web/src/app/main/my-duty/components/MyDutyListContainer.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/my-learning/components/MyLearningListContainer.tsx b/apps/web/src/app/main/my-learning/components/MyLearningListContainer.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/my-path/components/MyPathListContainer.tsx b/apps/web/src/app/main/my-path/components/MyPathListContainer.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/path/components/DeptInfo.tsx b/apps/web/src/app/main/path/components/DeptInfo.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/path/components/TermInfo.tsx b/apps/web/src/app/main/path/components/TermInfo.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/app/main/search/components/SearchContainer.tsx b/apps/web/src/app/main/search/components/SearchContainer.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/components/common/editor/MindEditor.tsx b/apps/web/src/components/common/editor/MindEditor.tsx index 985e320..9518d4f 100755 --- a/apps/web/src/components/common/editor/MindEditor.tsx +++ b/apps/web/src/components/common/editor/MindEditor.tsx @@ -20,9 +20,11 @@ import { useTusUpload } from "@web/src/hooks/useTusUpload"; import { useNavigate } from "react-router-dom"; import { useAuth } from "@web/src/providers/auth-provider"; import { MIND_OPTIONS } from "./constant"; -import { SaveOutlined } from "@ant-design/icons"; +import { LinkOutlined, SaveOutlined } from "@ant-design/icons"; import JoinButton from "../../models/course/detail/CourseOperationBtns/JoinButton"; import { CourseDetailContext } from "../../models/course/detail/PostDetailContext"; +import ReactDOM from "react-dom"; +import { createRoot } from "react-dom/client"; export default function MindEditor({ id }: { id?: string }) { const containerRef = useRef(null); const { @@ -57,6 +59,17 @@ export default function MindEditor({ id }: { id?: string }) { }); const { handleFileUpload } = useTusUpload(); const [form] = Form.useForm(); + const CustomLinkIconPlugin = (mind) => { + mind.bus.addListener('operation', async () => { + const hyperLinkElement = await document.querySelectorAll('.hyper-link'); + console.log('hyperLinkElement', hyperLinkElement); + hyperLinkElement.forEach((item) => { + const hyperLinkDom = createRoot(item) + hyperLinkDom.render() + }); + + }); + }; useEffect(() => { if (post?.id && id) { read.mutateAsync({ @@ -98,6 +111,7 @@ export default function MindEditor({ id }: { id?: string }) { nodeMenu: canEdit, // 禁用节点右键菜单 keypress: canEdit, // 禁用键盘快捷键 }); + mind.install(CustomLinkIconPlugin); mind.init(MindElixir.new("新思维导图")); containerRef.current.hidden = true; //挂载实例 @@ -173,16 +187,13 @@ export default function MindEditor({ id }: { id?: string }) { } console.log(result); }, - (error) => {}, + (error) => { }, `mind-thumb-${new Date().toString()}` ); }; useEffect(() => { containerRef.current.style.height = `${Math.floor(window.innerHeight - 271)}px`; }, []); - useEffect(()=>{ - console.log(canEdit,user?.id,post?.author?.id) - }) return (
{taxonomies && ( @@ -214,7 +225,7 @@ export default function MindEditor({ id }: { id?: string }) { multiple /> - + {post && id ? : <>}
{canEdit && ( diff --git a/apps/web/src/components/common/editor/constant.ts b/apps/web/src/components/common/editor/constant.ts old mode 100644 new mode 100755 diff --git a/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx b/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx index f95c29d..6231436 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx @@ -1,6 +1,6 @@ // components/CourseDetailDisplayArea.tsx import { motion, useScroll, useTransform } from "framer-motion"; -import React, { useContext, useRef, useState } from "react"; +import React, { useContext, useEffect, useRef, useState } from "react"; import { VideoPlayer } from "@web/src/components/presentation/video-player/VideoPlayer"; import { CourseDetailDescription } from "./CourseDetailDescription"; import { Course, LectureType, PostType } from "@nice/common"; @@ -40,7 +40,7 @@ export const CourseDetailDisplayArea: React.FC = () => { opacity: videoOpacity, }} className="w-full bg-black rounded-lg "> -
+
diff --git a/apps/web/src/components/models/course/detail/CourseOperationBtns/JoinButton.tsx b/apps/web/src/components/models/course/detail/CourseOperationBtns/JoinButton.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/components/models/post/PostCard.tsx b/apps/web/src/components/models/post/PostCard.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/components/models/post/PostSelect.tsx b/apps/web/src/components/models/post/PostSelect.tsx new file mode 100755 index 0000000..d5f5324 --- /dev/null +++ b/apps/web/src/components/models/post/PostSelect.tsx @@ -0,0 +1,12 @@ +import { api } from "@nice/client"; + +export default function PostSelect() { + const { data } = api.post.findMany.useQuery({ + where: { + title: { + contains: "" + } + } + }) + +} \ No newline at end of file diff --git a/apps/web/src/components/models/post/PostSelect/PostSelect.tsx b/apps/web/src/components/models/post/PostSelect/PostSelect.tsx index 63f4058..f97d148 100644 --- a/apps/web/src/components/models/post/PostSelect/PostSelect.tsx +++ b/apps/web/src/components/models/post/PostSelect/PostSelect.tsx @@ -91,6 +91,7 @@ export default function PostSelect({ dropdownStyle={{ minWidth: 200, // 设置合适的最小宽度 }} + autoClearSearchValue placeholder={placeholder} onChange={onChange} filterOption={false} diff --git a/apps/web/src/components/models/post/SubPost/CourseCard.tsx b/apps/web/src/components/models/post/SubPost/CourseCard.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/components/models/post/SubPost/PathCard.tsx b/apps/web/src/components/models/post/SubPost/PathCard.tsx old mode 100644 new mode 100755 diff --git a/apps/web/src/components/presentation/video-player/VideoDisplay.tsx b/apps/web/src/components/presentation/video-player/VideoDisplay.tsx index 32b1109..7260304 100755 --- a/apps/web/src/components/presentation/video-player/VideoDisplay.tsx +++ b/apps/web/src/components/presentation/video-player/VideoDisplay.tsx @@ -25,6 +25,7 @@ export const VideoDisplay: React.FC = ({ isDragging, setIsDragging, progressRef, + isPlaying } = useContext(VideoPlayerContext); // 处理进度条拖拽 @@ -191,9 +192,20 @@ export const VideoDisplay: React.FC = ({ }; }, [src, onError, autoPlay]); + const handleVideoClick = () => { + if (videoRef.current && isPlaying) { + videoRef.current.pause(); + setIsPlaying(false); + }else if (videoRef.current && !isPlaying) { + videoRef.current.play(); + setIsPlaying(true); + } + }; + return ( -
+