diff --git a/Dockerfile b/Dockerfile index e36b24a..95af1b4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -85,7 +85,10 @@ EXPOSE 80 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 # 设置工作目录 @@ -94,9 +97,11 @@ WORKDIR /usr/share/nginx/html # 设置环境变量 ENV NODE_ENV production -# 安装 envsubst 以支持环境变量替换 -RUN apk add --no-cache gettext +# 安装 envsubst 和 inotify-tools +RUN apk add --no-cache gettext inotify-tools + +# 创建 /data/uploads 目录 +RUN mkdir -p /data/uploads # 暴露 80 端口 -EXPOSE 80 - +EXPOSE 80 \ No newline at end of file diff --git a/apps/server/src/auth/auth.service.ts b/apps/server/src/auth/auth.service.ts index 40c71bb..a437b08 100755 --- a/apps/server/src/auth/auth.service.ts +++ b/apps/server/src/auth/auth.service.ts @@ -31,7 +31,7 @@ export class AuthService { return { isValid: false, error: FileValidationErrorType.INVALID_URI }; } const fileId = extractFileIdFromNginxUrl(params.originalUri); - console.log(params.originalUri, fileId); + console.log('auth', params.originalUri, fileId); const resource = await db.resource.findFirst({ where: { fileId } }); // 资源验证 @@ -170,13 +170,13 @@ export class AuthService { showname, department: deptId ? { - connect: { id: deptId }, - } + connect: { id: deptId }, + } : undefined, domain: deptId ? { - connect: { id: deptId }, - } + connect: { id: deptId }, + } : undefined, // domainId: data.deptId, meta: { diff --git a/apps/server/src/queue/models/post/utils.ts b/apps/server/src/queue/models/post/utils.ts index 4c620a2..c9d74a2 100644 --- a/apps/server/src/queue/models/post/utils.ts +++ b/apps/server/src/queue/models/post/utils.ts @@ -1,6 +1,5 @@ import { db, PostState, PostType, VisitType } from '@nice/common'; export async function updatePostViewCount(id: string, type: VisitType) { - console.log('updatePostViewCount', type); const totalViews = await db.visit.aggregate({ _sum: { views: true, diff --git a/apps/web/src/app/main/letter/write/SendCard.tsx b/apps/web/src/app/main/letter/write/SendCard.tsx index 521a14d..2e88110 100644 --- a/apps/web/src/app/main/letter/write/SendCard.tsx +++ b/apps/web/src/app/main/letter/write/SendCard.tsx @@ -42,17 +42,18 @@ export function SendCard({ staff, termId }: SendCardProps) {
-

+ {/* 修改后的职级显示部分 */} + {staff.meta?.rank && ( + + {staff.meta.rank} + + )} +

{staff?.showname || staff?.username}

-
- - - {staff.meta?.rank || '未设置职级'} - - +
{/* Contact Information */} diff --git a/apps/web/src/app/main/letter/write/page.tsx b/apps/web/src/app/main/letter/write/page.tsx index de44eae..505d2b6 100644 --- a/apps/web/src/app/main/letter/write/page.tsx +++ b/apps/web/src/app/main/letter/write/page.tsx @@ -1,7 +1,6 @@ -import { useState, useCallback, useEffect, useMemo } from "react"; +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"; @@ -9,7 +8,7 @@ import DepartmentSelect from "@web/src/components/models/department/department-s import debounce from "lodash/debounce"; import { SearchOutlined } from "@ant-design/icons"; import WriteHeader from "./WriteHeader"; -import { ObjectType, RoleName } from "@nice/common"; +import { RoleName, staffDetailSelect } from "@nice/common"; export default function WriteLetterPage() { const [searchParams] = useSearchParams(); @@ -23,18 +22,17 @@ export default function WriteLetterPage() { api.rolemap.getStaffIdsByRoleNames.useQuery({ roleNames: [RoleName.Leader, RoleName.Organization], }); - // eslint-disable-next-line react-hooks/exhaustive-deps - const { data, isLoading, error } = api.staff.findManyWithPagination.useQuery( { page: currentPage, pageSize, + select: staffDetailSelect, where: { id: enabledStaffIds ? { - in: enabledStaffIds, - } + in: enabledStaffIds, + } : undefined, deptId: selectedDept, OR: [ diff --git a/apps/web/src/components/common/uploader/AvatarUploader.tsx b/apps/web/src/components/common/uploader/AvatarUploader.tsx index cfcecc5..182314f 100644 --- a/apps/web/src/components/common/uploader/AvatarUploader.tsx +++ b/apps/web/src/components/common/uploader/AvatarUploader.tsx @@ -3,6 +3,7 @@ import { message, Progress, Spin, theme } from "antd"; import React, { useState, useEffect, useRef } from "react"; import { useTusUpload } from "@web/src/hooks/useTusUpload"; import { Avatar } from "antd/lib"; +import toast from "react-hot-toast"; export interface AvatarUploaderProps { value?: string; @@ -67,6 +68,7 @@ const AvatarUploader: React.FC = ({ url: result.url, compressedUrl: result.compressedUrl, })); + setUrl(result.url); setPreviewUrl(result.compressedUrl); // 直接使用 result 中的最新值 @@ -78,15 +80,13 @@ const AvatarUploader: React.FC = ({ file?.fileKey ); }); - // await new Promise((resolve) => setTimeout(resolve, 5000)); // 方法1:使用 await 暂停执行 - // 使用 resolved 的最新值调用 onChange - // 强制刷新 Avatar 组件 setAvatarKey((prev) => prev + 1); // 修改 key 强制重新挂载 onChange?.(uploadedUrl); - message.success("头像上传成功"); + console.log(uploadedUrl) + toast.success("头像上传成功"); } catch (error) { console.error("上传错误:", error); - message.error("头像上传失败"); + toast.error("头像上传失败"); setFile((prev) => ({ ...prev!, status: "error" })); } finally { setUploading(false); diff --git a/apps/web/src/components/models/post/detail/PostHeader/Content.tsx b/apps/web/src/components/models/post/detail/PostHeader/Content.tsx index cc75d39..1bd3d2d 100644 --- a/apps/web/src/components/models/post/detail/PostHeader/Content.tsx +++ b/apps/web/src/components/models/post/detail/PostHeader/Content.tsx @@ -9,7 +9,7 @@ export default function Content() { const [isExpanded, setIsExpanded] = useState(false); const contentWrapperRef = useRef(null); const [shouldCollapse, setShouldCollapse] = useState(false); - + console.log(post) useEffect(() => { if (contentWrapperRef.current) { const shouldCollapse = contentWrapperRef.current.scrollHeight > 150; diff --git a/apps/web/src/components/models/post/detail/PostResources.tsx b/apps/web/src/components/models/post/detail/PostResources.tsx index a9bfa71..f02631d 100644 --- a/apps/web/src/components/models/post/detail/PostResources.tsx +++ b/apps/web/src/components/models/post/detail/PostResources.tsx @@ -4,6 +4,7 @@ import { PostDto } from "@nice/common"; import { env } from "@web/src/env"; import { getFileIcon } from "./utils"; import { formatFileSize, getCompressedImageUrl } from '@nice/utils'; +import { useNavigate } from "react-router-dom"; export default function PostResources({ post }: { post: PostDto }) { @@ -29,7 +30,6 @@ export default function PostResources({ post }: { post: PostDto }) { const imageResources = resources.filter((res) => res.isImage); const fileResources = resources.filter((res) => !res.isImage); - return (
{imageResources.length > 0 && ( @@ -44,12 +44,9 @@ export default function PostResources({ post }: { post: PostDto }) { lg={6} xl={4} className="relative"> -
+
{ - console.log(e) - }} src={resource.url} alt={resource.title} preview={{ diff --git a/apps/web/src/components/models/post/editor/context/LetterEditorContext.tsx b/apps/web/src/components/models/post/editor/context/LetterEditorContext.tsx index 88bdaf0..e0ae398 100644 --- a/apps/web/src/components/models/post/editor/context/LetterEditorContext.tsx +++ b/apps/web/src/components/models/post/editor/context/LetterEditorContext.tsx @@ -45,7 +45,6 @@ export function LetterFormProvider({ const onSubmit = async (data: LetterFormData) => { try { - console.log("data", data); const receivers = data?.receivers; const terms = data?.terms; delete data.receivers; diff --git a/apps/web/src/hooks/useTusUpload.ts b/apps/web/src/hooks/useTusUpload.ts index f6fca26..dc90bcc 100644 --- a/apps/web/src/hooks/useTusUpload.ts +++ b/apps/web/src/hooks/useTusUpload.ts @@ -74,7 +74,8 @@ export function useTusUpload() { [fileKey]: progress, })); }, - onSuccess: async () => { + onSuccess: async (payload) => { + try { if (upload.url) { const fileId = getFileId(upload.url); diff --git a/config/nginx/conf.d/web.conf b/config/nginx/conf.d/web.conf index bf90259..697493e 100644 --- a/config/nginx/conf.d/web.conf +++ b/config/nginx/conf.d/web.conf @@ -65,10 +65,9 @@ server { sendfile on; tcp_nopush on; # 异步IO - aio on; + aio off; # 直接IO,提高大文件传输效率 - directio 512; - + directio off; # 文件访问认证 # 通过内部认证服务验证 auth_request /auth-file; @@ -77,9 +76,12 @@ server { auth_request_set $auth_user_id $upstream_http_x_user_id; auth_request_set $auth_resource_type $upstream_http_x_resource_type; # 不缓存 - expires 0; + # expires 0; # 私有缓存,禁止转换 - add_header Cache-Control "private, no-transform"; + # add_header Cache-Control "private, no-transform"; + open_file_cache off; # 禁用文件缓存 + add_header Cache-Control "no-cache, no-store, must-revalidate"; # 禁用浏览器缓存 + expires -1; # 立即过期 # 添加用户和资源类型头 add_header X-User-Id $auth_user_id; add_header X-Resource-Type $auth_resource_type; diff --git a/config/nginx/conf.d/web.template b/config/nginx/conf.d/web.template index 35c1d2b..2ffdfe8 100644 --- a/config/nginx/conf.d/web.template +++ b/config/nginx/conf.d/web.template @@ -68,7 +68,6 @@ server { aio on; # 直接IO,提高大文件传输效率 directio 512; - # 文件访问认证 # 通过内部认证服务验证 auth_request /auth-file; @@ -80,6 +79,8 @@ server { expires 0; # 私有缓存,禁止转换 add_header Cache-Control "private, no-transform"; + + expires -1; # 立即过期 # 添加用户和资源类型头 add_header X-User-Id $auth_user_id; add_header X-Resource-Type $auth_resource_type; diff --git a/packages/common/src/select.ts b/packages/common/src/select.ts index 4b3526a..634fbfd 100644 --- a/packages/common/src/select.ts +++ b/packages/common/src/select.ts @@ -1,5 +1,25 @@ import { Prisma } from "@prisma/client"; - +export const staffDetailSelect: Prisma.StaffSelect = { + id: true, + username: true, + department: { + select: { + id: true, + name: true + } + }, + showname: true, + phoneNumber: true, + deptId: true, + domain: { + select: { + id: true, + name: true + } + }, + domainId: true, + meta: true +} export const postDetailSelect: Prisma.PostSelect = { id: true, type: true,