diff --git a/apps/server/src/models/base/base.type.ts b/apps/server/src/models/base/base.type.ts index 878dffe..01254df 100644 --- a/apps/server/src/models/base/base.type.ts +++ b/apps/server/src/models/base/base.type.ts @@ -1,25 +1,27 @@ -import { db, Prisma, PrismaClient } from "@nice/common"; +import { db, Prisma, PrismaClient } from '@nice/common'; export type Operations = - | 'aggregate' - | 'count' - | 'create' - | 'createMany' - | 'delete' - | 'deleteMany' - | 'findFirst' - | 'findMany' - | 'findUnique' - | 'update' - | 'updateMany' - | 'upsert'; -export type DelegateFuncs = { [K in Operations]: (args: any) => Promise } + | 'aggregate' + | 'count' + | 'create' + | 'createMany' + | 'delete' + | 'deleteMany' + | 'findFirst' + | 'findMany' + | 'findUnique' + | 'update' + | 'updateMany' + | 'upsert'; +export type DelegateFuncs = { + [K in Operations]: (args: any) => Promise; +}; export type DelegateArgs = { - [K in keyof T]: T[K] extends (args: infer A) => Promise ? A : never; + [K in keyof T]: T[K] extends (args: infer A) => Promise ? A : never; }; export type DelegateReturnTypes = { - [K in keyof T]: T[K] extends (args: any) => Promise ? R : never; + [K in keyof T]: T[K] extends (args: any) => Promise ? R : never; }; export type WhereArgs = T extends { where?: infer W } ? W : never; @@ -28,17 +30,17 @@ export type DataArgs = T extends { data: infer D } ? D : never; export type IncludeArgs = T extends { include: infer I } ? I : never; export type OrderByArgs = T extends { orderBy: infer O } ? O : never; export type UpdateOrderArgs = { - id: string - overId: string -} + id: string; + overId: string; +}; export interface FindManyWithCursorType { - cursor?: string; - limit?: number; - where?: WhereArgs['findUnique']>; - select?: SelectArgs['findUnique']>; - orderBy?: OrderByArgs['findMany']> + cursor?: string; + limit?: number; + where?: WhereArgs['findUnique']>; + select?: SelectArgs['findUnique']>; + orderBy?: OrderByArgs['findMany']>; } export type TransactionType = Omit< - PrismaClient, - '$connect' | '$disconnect' | '$on' | '$transaction' | '$use' | '$extends' ->; \ No newline at end of file + PrismaClient, + '$connect' | '$disconnect' | '$on' | '$transaction' | '$use' | '$extends' +>; diff --git a/apps/server/src/models/post/post.router.ts b/apps/server/src/models/post/post.router.ts index c536977..e94dd57 100755 --- a/apps/server/src/models/post/post.router.ts +++ b/apps/server/src/models/post/post.router.ts @@ -12,13 +12,13 @@ const PostDeleteManyArgsSchema: ZodType = z.any(); const PostWhereInputSchema: ZodType = z.any(); const PostSelectSchema: ZodType = z.any(); const PostUpdateInputSchema: ZodType = z.any(); -const PostOrderBySchema: ZodType = z.any() +const PostOrderBySchema: ZodType = z.any(); @Injectable() export class PostRouter { constructor( private readonly trpc: TrpcService, private readonly postService: PostService, - ) { } + ) {} router = this.trpc.router({ create: this.trpc.protectProcedure .input(PostCreateArgsSchema) @@ -104,7 +104,7 @@ export class PostRouter { pageSize: z.number().optional(), where: PostWhereInputSchema.optional(), select: PostSelectSchema.optional(), - orderBy: PostOrderBySchema.optional() + orderBy: PostOrderBySchema.optional(), }), ) // Assuming StaffMethodSchema.findMany is the Zod schema for finding staffs by keyword .query(async ({ input, ctx }) => { diff --git a/apps/server/src/models/post/post.service.ts b/apps/server/src/models/post/post.service.ts index c599add..089f686 100755 --- a/apps/server/src/models/post/post.service.ts +++ b/apps/server/src/models/post/post.service.ts @@ -101,22 +101,31 @@ export class PostService extends BaseService { }); } async findManyWithPagination( - args: { page?: number; pageSize?: number; where?: Prisma.PostWhereInput; select?: Prisma.PostSelect; orderBy?: Prisma.PostOrderByWithRelationInput }, + args: { + page?: number; + pageSize?: number; + where?: Prisma.PostWhereInput; + select?: Prisma.PostSelect; + orderBy?: Prisma.PostOrderByWithRelationInput; + }, staff?: UserProfile, clientIp?: string, ) { if (!args.where) args.where = {}; args.where.OR = await this.preFilter(args.where.OR, staff); - return this.wrapResult(super.findManyWithPagination(args as any), async (result) => { - const { items } = result; - await Promise.all( - items.map(async (item) => { - await setPostRelation({ data: item, staff, clientIp }); - await this.setPerms(item, staff); - }), - ); - return { ...result, items }; - }); + return this.wrapResult( + super.findManyWithPagination(args as any), + async (result) => { + const { items } = result; + await Promise.all( + items.map(async (item) => { + await setPostRelation({ data: item, staff, clientIp }); + await this.setPerms(item, staff); + }), + ); + return { ...result, items }; + }, + ); } protected async setPerms(data: Post, staff?: UserProfile) { if (!staff) return; diff --git a/apps/server/src/models/staff/staff.router.ts b/apps/server/src/models/staff/staff.router.ts index c8d73dd..80e5bdc 100755 --- a/apps/server/src/models/staff/staff.router.ts +++ b/apps/server/src/models/staff/staff.router.ts @@ -12,13 +12,15 @@ const StaffWhereInputSchema: ZodType = z.any(); const StaffSelectSchema: ZodType = z.any(); const StaffUpdateInputSchema: ZodType = z.any(); const StaffFindManyArgsSchema: ZodType = z.any(); +const StaffOrderBySchema: ZodType = + z.any(); @Injectable() export class StaffRouter { constructor( private readonly trpc: TrpcService, private readonly staffService: StaffService, private readonly staffRowService: StaffRowService, - ) { } + ) {} router = this.trpc.router({ create: this.trpc.procedure @@ -78,12 +80,15 @@ export class StaffRouter { return this.staffService.updateOrder(input); }), findManyWithPagination: this.trpc.procedure - .input(z.object({ - page: z.number(), - pageSize: z.number().optional(), - where: StaffWhereInputSchema.optional(), - select: StaffSelectSchema.optional() - })) // Assuming StaffMethodSchema.findMany is the Zod schema for finding staffs by keyword + .input( + z.object({ + page: z.number(), + pageSize: z.number().optional(), + where: StaffWhereInputSchema.optional(), + select: StaffSelectSchema.optional(), + orderBy: StaffOrderBySchema.optional(), + }), + ) // Assuming StaffMethodSchema.findMany is the Zod schema for finding staffs by keyword .query(async ({ input }) => { return await this.staffService.findManyWithPagination(input); }), diff --git a/apps/server/src/models/staff/staff.service.ts b/apps/server/src/models/staff/staff.service.ts index a2d69fe..1d5850a 100755 --- a/apps/server/src/models/staff/staff.service.ts +++ b/apps/server/src/models/staff/staff.service.ts @@ -105,7 +105,7 @@ export class StaffService extends BaseService { * @returns 更新后的员工记录 */ async updateUserDomain(data: { domainId?: string }, staff?: UserProfile) { - let { domainId } = data; + const { domainId } = data; if (staff.domainId !== domainId) { const result = await this.update({ where: { id: staff.id }, @@ -120,14 +120,23 @@ export class StaffService extends BaseService { } } - async findManyWithPagination(args: { page?: number; pageSize?: number; where?: Prisma.StaffWhereInput; select?: Prisma.StaffSelect; }) { + async findManyWithPagination(args: { + page?: number; + pageSize?: number; + where?: Prisma.StaffWhereInput; + select?: Prisma.StaffSelect; + orderBy?: Prisma.StaffOrderByWithRelationInput; + }) { if (args.where.deptId && typeof args.where.deptId === 'string') { - const childDepts = await this.departmentService.getDescendantIds(args.where.deptId, true); + const childDepts = await this.departmentService.getDescendantIds( + args.where.deptId, + true, + ); args.where.deptId = { - in: childDepts - } + in: childDepts, + }; } - - return super.findManyWithPagination(args) + + return super.findManyWithPagination(args as any); } } diff --git a/apps/web/src/app/main/letter/write/page.tsx b/apps/web/src/app/main/letter/write/page.tsx index 39b237d..a9c6d87 100644 --- a/apps/web/src/app/main/letter/write/page.tsx +++ b/apps/web/src/app/main/letter/write/page.tsx @@ -1,139 +1,149 @@ -import { useState, useCallback, useEffect } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { useSearchParams } from 'react-router-dom'; +import { useState, useCallback, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { useSearchParams } from "react-router-dom"; -import { SendCard } from './SendCard'; -import { Spin, Empty, Input, Alert, Pagination } from 'antd'; -import { api, useTerm } from '@nice/client'; -import DepartmentSelect from '@web/src/components/models/department/department-select'; -import debounce from 'lodash/debounce'; -import { SearchOutlined } from '@ant-design/icons'; -import WriteHeader from './WriteHeader'; +import { SendCard } from "./SendCard"; +import { Spin, Empty, Input, Alert, Pagination } from "antd"; +import { api, useTerm } from "@nice/client"; +import DepartmentSelect from "@web/src/components/models/department/department-select"; +import debounce from "lodash/debounce"; +import { SearchOutlined } from "@ant-design/icons"; +import WriteHeader from "./WriteHeader"; export default function WriteLetterPage() { - const [searchParams] = useSearchParams(); - const termId = searchParams.get('termId'); - const [searchQuery, setSearchQuery] = useState(''); - const [selectedDept, setSelectedDept] = useState(); - const [currentPage, setCurrentPage] = useState(1); - const pageSize = 10; - const { getTerm } = useTerm() + const [searchParams] = useSearchParams(); + const termId = searchParams.get("termId"); + const [searchQuery, setSearchQuery] = useState(""); + const [selectedDept, setSelectedDept] = useState(); + const [currentPage, setCurrentPage] = useState(1); + const pageSize = 10; + const { getTerm } = useTerm(); - const { data, isLoading, error } = api.staff.findManyWithPagination.useQuery({ - page: currentPage, - pageSize, - - where: { - deptId: selectedDept, - OR: [{ - showname: { - contains: searchQuery - } - }, { - username: { - contains: searchQuery - } - }] - } - }); + const { data, isLoading, error } = + api.staff.findManyWithPagination.useQuery({ + page: currentPage, + pageSize, + where: { + deptId: selectedDept, + OR: [ + { + showname: { + contains: searchQuery, + }, + }, + { + username: { + contains: searchQuery, + }, + }, + ], + }, + orderBy: { + order: "desc", + }, + // orderBy:{ - const resetPage = useCallback(() => { - setCurrentPage(1); - }, []); + // } + }); - // Reset page when search or department changes - useEffect(() => { - resetPage(); - }, [searchQuery, selectedDept, resetPage]); + const resetPage = useCallback(() => { + setCurrentPage(1); + }, []); - return ( -
- -
-
- {/* Search and Filter Section */} -
- - } - placeholder="搜索领导姓名或职级..." - onChange={debounce((e) => setSearchQuery(e.target.value), 300)} + // Reset page when search or department changes + useEffect(() => { + resetPage(); + }, [searchQuery, selectedDept, resetPage]); - size="large" - /> + return ( +
+ +
+
+ {/* Search and Filter Section */} +
+ + + } + placeholder="搜索领导姓名或职级..." + onChange={debounce( + (e) => setSearchQuery(e.target.value), + 300 + )} + size="large" + /> +
-
+ {error && ( + + )} +
- {error && ( - - )} -
+ + {isLoading ? ( +
+ +
+ ) : data?.items.length > 0 ? ( + + {data?.items.map((item: any) => ( + + ))} + + ) : ( + + + + )} +
- - {isLoading ? ( -
- -
- ) : data?.items.length > 0 ? ( - - {data?.items.map((item: any) => ( - - ))} - - ) : ( - - - - )} -
- - {/* Pagination */} - {data?.items.length > 0 && ( -
- { - setCurrentPage(page); - window.scrollTo(0, 0); - }} - showSizeChanger={false} - showTotal={(total) => `共 ${total} 条记录`} - /> -
- )} -
-
- ); + {/* Pagination */} + {data?.items.length > 0 && ( +
+ { + setCurrentPage(page); + window.scrollTo(0, 0); + }} + showSizeChanger={false} + showTotal={(total) => `共 ${total} 条记录`} + /> +
+ )} +
+
+ ); } diff --git a/apps/web/src/components/models/post/list/LetterList.tsx b/apps/web/src/components/models/post/list/LetterList.tsx index 0e60ef6..b11d055 100644 --- a/apps/web/src/components/models/post/list/LetterList.tsx +++ b/apps/web/src/components/models/post/list/LetterList.tsx @@ -1,113 +1,114 @@ -import { useState, useEffect, useMemo } from 'react'; -import { Input, Pagination, Empty, Spin } from 'antd'; +import { useState, useEffect, useMemo } from "react"; +import { Input, Pagination, Empty, Spin } from "antd"; import { api, RouterInputs } from "@nice/client"; import { LetterCard } from "../LetterCard"; import { NonVoid } from "@nice/utils"; -import { SearchOutlined } from '@ant-design/icons'; -import debounce from 'lodash/debounce'; -import { postDetailSelect } from '@nice/common'; -export default function LetterList({ params }: { params: NonVoid }) { - const [searchText, setSearchText] = useState(''); - const [currentPage, setCurrentPage] = useState(1); +import { SearchOutlined } from "@ant-design/icons"; +import debounce from "lodash/debounce"; +import { postDetailSelect } from "@nice/common"; +export default function LetterList({ + params, +}: { + params: NonVoid; +}) { + const [searchText, setSearchText] = useState(""); + const [currentPage, setCurrentPage] = useState(1); - const { data, isLoading } = api.post.findManyWithPagination.useQuery({ - page: currentPage, - pageSize: params.pageSize, - where: { - OR: [{ - title: { - contains: searchText - } - }], - ...params?.where - }, - orderBy: { - updatedAt: "desc" - }, - select: { - ...postDetailSelect, - ...params.select - } - }); + const { data, isLoading } = api.post.findManyWithPagination.useQuery({ + page: currentPage, + pageSize: params.pageSize, + where: { + OR: [ + { + title: { + contains: searchText, + }, + }, + ], + ...params?.where, + }, + orderBy: { + updatedAt: "desc", + }, + select: { + ...postDetailSelect, + ...params.select, + }, + }); - const debouncedSearch = useMemo( - () => - debounce((value: string) => { - setSearchText(value); - setCurrentPage(1); - }, 300), - [] - ); - // Cleanup debounce on unmount - useEffect(() => { - return () => { - debouncedSearch.cancel(); - }; - }, [debouncedSearch]); - const handleSearch = (value: string) => { - debouncedSearch(value); - }; + const debouncedSearch = useMemo( + () => + debounce((value: string) => { + setSearchText(value); + setCurrentPage(1); + }, 300), + [] + ); + // Cleanup debounce on unmount + useEffect(() => { + return () => { + debouncedSearch.cancel(); + }; + }, [debouncedSearch]); + const handleSearch = (value: string) => { + debouncedSearch(value); + }; - const handlePageChange = (page: number) => { - setCurrentPage(page); - // Scroll to top when page changes - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; + const handlePageChange = (page: number) => { + setCurrentPage(page); + // Scroll to top when page changes + window.scrollTo({ top: 0, behavior: "smooth" }); + }; - return ( -
- {/* Search Bar */} -
- handleSearch(e.target.value)} - prefix={} - /> -
+ return ( +
+ {/* Search Bar */} +
+ handleSearch(e.target.value)} + prefix={} + /> +
- {/* Content Area */} -
- {isLoading ? ( -
- -
- ) : data?.items.length ? ( - <> -
- {data.items.map((letter: any) => ( - - ))} -
-
- -
- - ) : ( -
- -
- )} -
- - -
- ); + {/* Content Area */} +
+ {isLoading ? ( +
+ +
+ ) : data?.items.length ? ( + <> +
+ {data.items.map((letter: any) => ( + + ))} +
+
+ +
+ + ) : ( +
+ +
+ )} +
+
+ ); } diff --git a/packages/utils/package.json b/packages/utils/package.json index 8f3fd0e..c02c2c3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -8,6 +8,7 @@ "scripts": { "build": "tsup", "dev": "tsup --watch", + "dev-static": "tsup --no-watch", "clean": "rimraf dist", "typecheck": "tsc --noEmit" },