This commit is contained in:
longdayi 2025-01-27 00:29:19 +08:00
parent 406fa8014f
commit 4d4f8f2cda
13 changed files with 67 additions and 44 deletions

View File

@ -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

View File

@ -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: {

View File

@ -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,

View File

@ -42,17 +42,18 @@ export function SendCard({ staff, termId }: SendCardProps) {
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-4">
<div>
<div className="flex items-center gap-3 mb-2">
<h3 className="text-2xl font-semibold text-gray-700">
{/* 修改后的职级显示部分 */}
{staff.meta?.rank && (
<span className="text-2xl font-bold text-primary tracking-wide mr-2">
{staff.meta.rank}
</span>
)}
<h3 className="text-2xl font-semibold text-primary">
{staff?.showname || staff?.username}
</h3>
</div>
</div>
<Tooltip title="职级">
<span className="inline-flex items-center px-4 py-1.5 text-sm font-medium bg-gradient-to-r from-blue-50 to-blue-100 text-primary rounded-full hover:from-blue-100 hover:to-blue-200 transition-colors shadow-sm">
{staff.meta?.rank || '未设置职级'}
</span>
</Tooltip>
</div>
{/* Contact Information */}

View File

@ -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: [

View File

@ -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<AvatarUploaderProps> = ({
url: result.url,
compressedUrl: result.compressedUrl,
}));
setUrl(result.url);
setPreviewUrl(result.compressedUrl);
// 直接使用 result 中的最新值
@ -78,15 +80,13 @@ const AvatarUploader: React.FC<AvatarUploaderProps> = ({
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);

View File

@ -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;

View File

@ -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 (
<div className="space-y-6">
{imageResources.length > 0 && (
@ -44,12 +44,9 @@ export default function PostResources({ post }: { post: PostDto }) {
lg={6}
xl={4}
className="relative">
<div className="relative aspect-square rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow duration-300 bg-gray-100">
<div className="relative aspect-square rounded-lg overflow-hidden bg-gray-100">
<div className="w-full h-full">
<Image
onError={(e) => {
console.log(e)
}}
src={resource.url}
alt={resource.title}
preview={{

View File

@ -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;

View File

@ -74,7 +74,8 @@ export function useTusUpload() {
[fileKey]: progress,
}));
},
onSuccess: async () => {
onSuccess: async (payload) => {
try {
if (upload.url) {
const fileId = getFileId(upload.url);

View File

@ -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;

View File

@ -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;

View File

@ -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,