From f8f3e7985e507ccd3484cc34bce861c7ebc3275f Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 09:11:15 +0800 Subject: [PATCH 1/3] add --- apps/server/src/models/visit/visit.service.ts | 7 +++++++ apps/server/src/queue/models/post/utils.ts | 2 +- apps/web/src/app/main/layout/UserMenu/types.ts | 3 ++- .../models/course/detail/CourseDetailDescription.tsx | 2 +- .../detail/CourseDetailHeader/CourseDetailHeader.tsx | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/server/src/models/visit/visit.service.ts b/apps/server/src/models/visit/visit.service.ts index 4742c61..20607e3 100755 --- a/apps/server/src/models/visit/visit.service.ts +++ b/apps/server/src/models/visit/visit.service.ts @@ -40,7 +40,11 @@ export class VisitService extends BaseService { id: postId, visitType: args.data.type, // 直接复用传入的类型 }); + EventBus.emit('updateTotalCourseViewCount', { + visitType: args.data.type, // 直接复用传入的类型 + }); } + return result; } async createMany(args: Prisma.VisitCreateManyArgs, staff?: UserProfile) { @@ -138,6 +142,9 @@ export class VisitService extends BaseService { id: args?.where?.postId as string, visitType: args.where.type as any, // 直接复用传入的类型 }); + EventBus.emit('updateTotalCourseViewCount', { + visitType: args.where.type as any, // 直接复用传入的类型 + }); } } return superDetele; diff --git a/apps/server/src/queue/models/post/utils.ts b/apps/server/src/queue/models/post/utils.ts index 115c323..7f2b69d 100644 --- a/apps/server/src/queue/models/post/utils.ts +++ b/apps/server/src/queue/models/post/utils.ts @@ -38,7 +38,7 @@ export async function updateTotalCourseViewCount(type: VisitType) { data: { meta: { ...baseSeting, - reads: totalViews, + reads: totalViews._sum.views, }, }, }); diff --git a/apps/web/src/app/main/layout/UserMenu/types.ts b/apps/web/src/app/main/layout/UserMenu/types.ts index 9809554..f21be44 100644 --- a/apps/web/src/app/main/layout/UserMenu/types.ts +++ b/apps/web/src/app/main/layout/UserMenu/types.ts @@ -1,5 +1,6 @@ +import React from "react"; export interface MenuItemType { - icon: JSX.Element; + icon: React.; label: string; action: () => void; } diff --git a/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx b/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx index e33e445..feba41d 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx @@ -47,7 +47,7 @@ export const CourseDetailDescription: React.FC = () => {
{course?.subTitle}
-
{course?.meta?.views}
+
{course?.meta?.views || 0}
diff --git a/apps/web/src/components/models/course/detail/CourseDetailHeader/CourseDetailHeader.tsx b/apps/web/src/components/models/course/detail/CourseDetailHeader/CourseDetailHeader.tsx index 554e5b7..7e708e1 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailHeader/CourseDetailHeader.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailHeader/CourseDetailHeader.tsx @@ -21,7 +21,7 @@ export function CourseDetailHeader() { return (
-
+
{ From 3432b1af791ec3eb7824fa2da08f16ee5def8e66 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 09:55:36 +0800 Subject: [PATCH 2/3] add --- apps/server/src/queue/models/post/utils.ts | 29 +++++++++++++++---- .../app/main/home/components/HeroSection.tsx | 27 +++++++++-------- .../web/src/app/main/layout/UserMenu/types.ts | 4 +-- .../course/detail/CourseDetailSkeleton.tsx | 1 + apps/web/src/hooks/useTusUpload.ts | 2 +- packages/client/src/api/hooks/useAppConfig.ts | 15 +++++++++- packages/common/src/types.ts | 7 ++++- 7 files changed, 61 insertions(+), 24 deletions(-) diff --git a/apps/server/src/queue/models/post/utils.ts b/apps/server/src/queue/models/post/utils.ts index 7f2b69d..0b25170 100644 --- a/apps/server/src/queue/models/post/utils.ts +++ b/apps/server/src/queue/models/post/utils.ts @@ -7,11 +7,18 @@ import { VisitType, } from '@nice/common'; export async function updateTotalCourseViewCount(type: VisitType) { - const courses = await db.post.findMany({ - where: { type: PostType.COURSE }, - select: { id: true }, + const posts = await db.post.findMany({ + where: { + type: { in: [PostType.COURSE, PostType.LECTURE] }, + deletedAt: null, + }, + select: { id: true, type: true }, }); - const courseIds = courses.map((course) => course.id); + + const courseIds = posts + .filter((post) => post.type === PostType.COURSE) + .map((course) => course.id); + const lectures = posts.filter((post) => post.type === PostType.LECTURE); const totalViews = await db.visit.aggregate({ _sum: { views: true, @@ -30,6 +37,10 @@ export async function updateTotalCourseViewCount(type: VisitType) { meta: true, }, }); + const staffs = await db.staff.count({ + where: { deletedAt: null }, + }); + const baseSeting = appConfig.meta as BaseSetting; await db.appConfig.update({ where: { @@ -38,7 +49,15 @@ export async function updateTotalCourseViewCount(type: VisitType) { data: { meta: { ...baseSeting, - reads: totalViews._sum.views, + appConfig: { + ...(baseSeting?.appConfig || {}), + statistics: { + reads: totalViews._sum.views || 0, + courses: courseIds?.length || 0, + staffs: staffs || 0, + lectures: lectures?.length || 0, + }, + }, }, }, }); diff --git a/apps/web/src/app/main/home/components/HeroSection.tsx b/apps/web/src/app/main/home/components/HeroSection.tsx index 5a58d12..0399c32 100755 --- a/apps/web/src/app/main/home/components/HeroSection.tsx +++ b/apps/web/src/app/main/home/components/HeroSection.tsx @@ -45,16 +45,16 @@ const carouselItems: CarouselItem[] = [ }, ]; -const platformStats: PlatformStat[] = [ - { icon: , value: "50,000+", label: "注册学员" }, - { icon: , value: "1,000+", label: "精品课程" }, - // { icon: , value: '98%', label: '好评度' }, - { icon: , value: "100万+", label: "观看次数" }, -]; - const HeroSection = () => { const carouselRef = useRef(null); + const { statistics, baseSetting } = useAppConfig(); + const platformStats: PlatformStat[] = [ + { icon: , value: "50,000+", label: "注册学员" }, + { icon: , value: "1,000+", label: "精品课程" }, + // { icon: , value: '98%', label: '好评度' }, + { icon: , value: "4552", label: "观看次数" }, + ]; const handlePrev = useCallback(() => { carouselRef.current?.prev(); }, []); @@ -74,8 +74,8 @@ const HeroSection = () => { dots={{ className: "carousel-dots !bottom-32 !z-20", }}> - {Array.isArray(carouselItems)? - (carouselItems.map((item, index) => ( + {Array.isArray(carouselItems) ? ( + carouselItems.map((item, index) => (
{ {/* Content Container */}
- ))) - :( -
- ) - } + )) + ) : ( +
+ )} {/* Navigation Buttons */} diff --git a/apps/web/src/app/main/layout/UserMenu/types.ts b/apps/web/src/app/main/layout/UserMenu/types.ts index f21be44..dfe4b00 100644 --- a/apps/web/src/app/main/layout/UserMenu/types.ts +++ b/apps/web/src/app/main/layout/UserMenu/types.ts @@ -1,6 +1,6 @@ -import React from "react"; +import React, { ReactNode } from "react"; export interface MenuItemType { - icon: React.; + icon: ReactNode; label: string; action: () => void; } diff --git a/apps/web/src/components/models/course/detail/CourseDetailSkeleton.tsx b/apps/web/src/components/models/course/detail/CourseDetailSkeleton.tsx index 95b1049..ad58cb8 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailSkeleton.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailSkeleton.tsx @@ -2,6 +2,7 @@ import { SkeletonItem, SkeletonSection, } from "@web/src/components/presentation/Skeleton"; +import { api } from "packages/client/dist"; export const CourseDetailSkeleton = () => { return ( diff --git a/apps/web/src/hooks/useTusUpload.ts b/apps/web/src/hooks/useTusUpload.ts index a4589a5..3f6d038 100755 --- a/apps/web/src/hooks/useTusUpload.ts +++ b/apps/web/src/hooks/useTusUpload.ts @@ -15,7 +15,7 @@ export function useTusUpload() { >({}); const [isUploading, setIsUploading] = useState(false); const [uploadError, setUploadError] = useState(null); - + const getFileId = (url: string) => { const parts = url.split("/"); const uploadIndex = parts.findIndex((part) => part === "upload"); diff --git a/packages/client/src/api/hooks/useAppConfig.ts b/packages/client/src/api/hooks/useAppConfig.ts index 5be578e..f38b6de 100755 --- a/packages/client/src/api/hooks/useAppConfig.ts +++ b/packages/client/src/api/hooks/useAppConfig.ts @@ -10,6 +10,7 @@ export function useAppConfig() { api.app_config.findFirst.useQuery({ where: { slug: AppConfigSlug.BASE_SETTING }, }); + const handleMutationSuccess = useCallback(() => { utils.app_config.invalidate(); }, [utils]); @@ -26,7 +27,8 @@ export function useAppConfig() { }); useEffect(() => { if (data?.meta) { - setBaseSetting(JSON.parse(data?.meta)); + // console.log(JSON.parse(data?.meta)); + setBaseSetting(data?.meta); } }, [data, isLoading]); const splashScreen = useMemo(() => { @@ -38,6 +40,16 @@ export function useAppConfig() { const slides = useMemo(() => { return baseSetting?.appConfig?.slides || []; }, [baseSetting]); + const statistics = useMemo(() => { + return ( + baseSetting?.appConfig?.statistics || { + reads: 0, + staffs: 0, + courses: 0, + lectures: 0, + } + ); + }, [baseSetting]); return { create, deleteMany, @@ -47,5 +59,6 @@ export function useAppConfig() { devDept, isLoading, slides, + statistics, }; } diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index 2a081c0..0207fb7 100755 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -44,7 +44,12 @@ export interface BaseSetting { splashScreen?: string; devDept?: string; slides?: []; - reads?: number; + statistics?: { + reads?: number; + courses?: number; + lectures?: number; + staffs?: number; + }; }; } export type RowModelResult = { From d5aa2f02d11a6cb5548cb33faa2e7fdbe5135a03 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 10:00:02 +0800 Subject: [PATCH 3/3] add --- .../components/models/staff/staff-form.tsx | 75 ++++++++++++------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/apps/web/src/components/models/staff/staff-form.tsx b/apps/web/src/components/models/staff/staff-form.tsx index 1dc4920..513f08c 100755 --- a/apps/web/src/components/models/staff/staff-form.tsx +++ b/apps/web/src/components/models/staff/staff-form.tsx @@ -1,10 +1,11 @@ import { Button, Form, Input, Spin, Switch, message } from "antd"; -import { useContext, useEffect} from "react"; +import { useContext, useEffect } from "react"; import { useStaff } from "@nice/client"; import DepartmentSelect from "../department/department-select"; -import { api } from "@nice/client" +import { api } from "@nice/client"; import { StaffEditorContext } from "./staff-editor"; import { useAuth } from "@web/src/providers/auth-provider"; +import AvatarUploader from "../../common/uploader/AvatarUploader"; export default function StaffForm() { const { create, update } = useStaff(); // Ensure you have these methods in your hooks const { @@ -21,6 +22,7 @@ export default function StaffForm() { { where: { id: editId } }, { enabled: !!editId } ); + const { isRoot } = useAuth(); async function handleFinish(values: any) { const { @@ -31,8 +33,9 @@ export default function StaffForm() { password, phoneNumber, officerId, - enabled - } = values + enabled, + avatar, + } = values; setFormLoading(true); try { if (data && editId) { @@ -46,8 +49,9 @@ export default function StaffForm() { password, phoneNumber, officerId, - enabled - } + enabled, + avatar, + }, }); } else { await create.mutateAsync({ @@ -58,8 +62,9 @@ export default function StaffForm() { domainId: fieldDomainId ? fieldDomainId : domainId, password, officerId, - phoneNumber - } + phoneNumber, + avatar, + }, }); form.resetFields(); if (deptId) form.setFieldValue("deptId", deptId); @@ -77,13 +82,14 @@ export default function StaffForm() { useEffect(() => { form.resetFields(); if (data && editId) { - form.setFieldValue("username", data.username); - form.setFieldValue("showname", data.showname); - form.setFieldValue("domainId", data.domainId); - form.setFieldValue("deptId", data.deptId); - form.setFieldValue("officerId", data.officerId); - form.setFieldValue("phoneNumber", data.phoneNumber); - form.setFieldValue("enabled", data.enabled) + form.setFieldValue("username", data?.username); + form.setFieldValue("showname", data?.showname); + form.setFieldValue("domainId", data?.domainId); + form.setFieldValue("deptId", data?.deptId); + form.setFieldValue("officerId", data?.officerId); + form.setFieldValue("phoneNumber", data?.phoneNumber); + form.setFieldValue("enabled", data?.enabled); + form.setFieldValue("avatar", data?.avatar); } }, [data]); useEffect(() => { @@ -99,6 +105,7 @@ export default function StaffForm() {
)} +
+ + + {canManageAnyStaff && ( - @@ -136,7 +147,8 @@ export default function StaffForm() { rules={[{ required: true }]} name={"showname"} label="姓名"> - @@ -146,8 +158,8 @@ export default function StaffForm() { { required: false, pattern: /^\d{5,18}$/, - message: "请输入正确的证件号(数字)" - } + message: "请输入正确的证件号(数字)", + }, ]} name={"officerId"} label="证件号"> @@ -158,20 +170,29 @@ export default function StaffForm() { { required: false, pattern: /^\d{6,11}$/, - message: "请输入正确的手机号(数字)" - } + message: "请输入正确的手机号(数字)", + }, ]} name={"phoneNumber"} label="手机号"> - + - + - {editId && - - } + {editId && ( + + + + )}
);