데이터 테이블 첨부파일 연계
This commit is contained in:
@@ -62,21 +62,45 @@ const upload = multer({
|
||||
fileSize: 50 * 1024 * 1024, // 50MB 제한
|
||||
},
|
||||
fileFilter: (req, file, cb) => {
|
||||
// 파일 타입 검증
|
||||
const allowedTypes = [
|
||||
// 프론트엔드에서 전송된 accept 정보 확인
|
||||
const acceptHeader = req.body?.accept;
|
||||
console.log("🔍 파일 타입 검증:", {
|
||||
fileName: file.originalname,
|
||||
mimeType: file.mimetype,
|
||||
acceptFromFrontend: acceptHeader,
|
||||
});
|
||||
|
||||
// 프론트엔드에서 */* 또는 * 허용한 경우 모든 파일 허용
|
||||
if (
|
||||
acceptHeader &&
|
||||
(acceptHeader.includes("*/*") || acceptHeader.includes("*"))
|
||||
) {
|
||||
console.log("✅ 와일드카드 허용: 모든 파일 타입 허용");
|
||||
cb(null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// 기본 허용 파일 타입
|
||||
const defaultAllowedTypes = [
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/gif",
|
||||
"text/html", // HTML 파일 추가
|
||||
"text/plain", // 텍스트 파일 추가
|
||||
"application/pdf",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/zip", // ZIP 파일 추가
|
||||
"application/x-zip-compressed", // ZIP 파일 (다른 MIME 타입)
|
||||
];
|
||||
|
||||
if (allowedTypes.includes(file.mimetype)) {
|
||||
if (defaultAllowedTypes.includes(file.mimetype)) {
|
||||
console.log("✅ 기본 허용 파일 타입:", file.mimetype);
|
||||
cb(null, true);
|
||||
} else {
|
||||
console.log("❌ 허용되지 않는 파일 타입:", file.mimetype);
|
||||
cb(new Error("허용되지 않는 파일 타입입니다."));
|
||||
}
|
||||
},
|
||||
@@ -116,11 +140,27 @@ export const uploadFiles = async (
|
||||
}
|
||||
|
||||
const files = req.files as Express.Multer.File[];
|
||||
|
||||
// 파라미터 확인 및 로깅
|
||||
console.log("📤 파일 업로드 요청 수신:", {
|
||||
filesCount: files?.length || 0,
|
||||
bodyKeys: Object.keys(req.body),
|
||||
fullBody: req.body, // 전체 body 내용 확인
|
||||
});
|
||||
|
||||
const {
|
||||
docType = "DOCUMENT",
|
||||
docTypeName = "일반 문서",
|
||||
targetObjid,
|
||||
parentTargetObjid,
|
||||
// 테이블 연결 정보 (새로 추가)
|
||||
linkedTable,
|
||||
linkedField,
|
||||
recordId,
|
||||
autoLink,
|
||||
// 가상 파일 컬럼 정보
|
||||
columnName,
|
||||
isVirtualFileColumn,
|
||||
} = req.body;
|
||||
|
||||
// 회사코드와 작성자 정보 결정 (우선순위: 요청 body > 사용자 토큰 정보 > 기본값)
|
||||
@@ -128,6 +168,26 @@ export const uploadFiles = async (
|
||||
req.body.companyCode || (req.user as any)?.companyCode || "DEFAULT";
|
||||
const writer = req.body.writer || (req.user as any)?.userId || "system";
|
||||
|
||||
// 자동 연결 로직 - target_objid 자동 생성
|
||||
let finalTargetObjid = targetObjid;
|
||||
if (autoLink === "true" && linkedTable && recordId) {
|
||||
// 가상 파일 컬럼의 경우 컬럼명도 포함한 target_objid 생성
|
||||
if (isVirtualFileColumn === "true" && columnName) {
|
||||
finalTargetObjid = `${linkedTable}:${recordId}:${columnName}`;
|
||||
} else {
|
||||
finalTargetObjid = `${linkedTable}:${recordId}`;
|
||||
}
|
||||
|
||||
console.log("🔗 자동 연결 활성화:", {
|
||||
linkedTable,
|
||||
linkedField,
|
||||
recordId,
|
||||
columnName,
|
||||
isVirtualFileColumn,
|
||||
generatedTargetObjid: finalTargetObjid,
|
||||
});
|
||||
}
|
||||
|
||||
console.log("🔍 사용자 정보 결정:", {
|
||||
bodyCompanyCode: req.body.companyCode,
|
||||
userCompanyCode: (req.user as any)?.companyCode,
|
||||
@@ -185,7 +245,7 @@ export const uploadFiles = async (
|
||||
generateUUID().replace(/-/g, "").substring(0, 15),
|
||||
16
|
||||
),
|
||||
target_objid: targetObjid,
|
||||
target_objid: finalTargetObjid,
|
||||
saved_file_name: file.filename,
|
||||
real_file_name: file.originalname,
|
||||
doc_type: docType,
|
||||
@@ -290,6 +350,86 @@ export const deleteFile = async (
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 테이블 연결된 파일 조회
|
||||
*/
|
||||
export const getLinkedFiles = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const { tableName, recordId } = req.params;
|
||||
|
||||
console.log("📎 연결된 파일 조회 요청:", {
|
||||
tableName,
|
||||
recordId,
|
||||
});
|
||||
|
||||
// target_objid 생성 (테이블명:레코드ID 형식)
|
||||
const baseTargetObjid = `${tableName}:${recordId}`;
|
||||
|
||||
console.log("🔍 파일 조회 쿼리:", {
|
||||
tableName,
|
||||
recordId,
|
||||
baseTargetObjid,
|
||||
queryPattern: `${baseTargetObjid}%`,
|
||||
});
|
||||
|
||||
// 기본 target_objid와 파일 컬럼 패턴 모두 조회 (tableName:recordId% 패턴)
|
||||
const files = await prisma.attach_file_info.findMany({
|
||||
where: {
|
||||
target_objid: {
|
||||
startsWith: baseTargetObjid, // tableName:recordId로 시작하는 모든 파일
|
||||
},
|
||||
status: "ACTIVE",
|
||||
},
|
||||
orderBy: {
|
||||
regdate: "desc",
|
||||
},
|
||||
});
|
||||
|
||||
console.log("📁 조회된 파일 목록:", {
|
||||
foundFiles: files.length,
|
||||
targetObjids: files.map((f) => f.target_objid),
|
||||
});
|
||||
|
||||
const fileList = files.map((file: any) => ({
|
||||
objid: file.objid.toString(),
|
||||
savedFileName: file.saved_file_name,
|
||||
realFileName: file.real_file_name,
|
||||
fileSize: Number(file.file_size),
|
||||
fileExt: file.file_ext,
|
||||
filePath: file.file_path,
|
||||
docType: file.doc_type,
|
||||
docTypeName: file.doc_type_name,
|
||||
targetObjid: file.target_objid,
|
||||
parentTargetObjid: file.parent_target_objid,
|
||||
writer: file.writer,
|
||||
regdate: file.regdate?.toISOString(),
|
||||
status: file.status,
|
||||
}));
|
||||
|
||||
console.log("✅ 연결된 파일 조회 완료:", {
|
||||
baseTargetObjid,
|
||||
fileCount: fileList.length,
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
files: fileList,
|
||||
totalCount: fileList.length,
|
||||
targetObjid: baseTargetObjid, // 기준 target_objid 반환
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("연결된 파일 조회 오류:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: "연결된 파일 조회 중 오류가 발생했습니다.",
|
||||
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 파일 목록 조회
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
deleteFile,
|
||||
getFileList,
|
||||
downloadFile,
|
||||
getLinkedFiles,
|
||||
uploadMiddleware,
|
||||
} from "../controllers/fileController";
|
||||
import { authenticateToken } from "../middleware/authMiddleware";
|
||||
@@ -28,6 +29,13 @@ router.post("/upload", uploadMiddleware, uploadFiles);
|
||||
*/
|
||||
router.get("/", getFileList);
|
||||
|
||||
/**
|
||||
* @route GET /api/files/linked/:tableName/:recordId
|
||||
* @desc 테이블 연결된 파일 조회
|
||||
* @access Private
|
||||
*/
|
||||
router.get("/linked/:tableName/:recordId", getLinkedFiles);
|
||||
|
||||
/**
|
||||
* @route DELETE /api/files/:objid
|
||||
* @desc 파일 삭제 (논리적 삭제)
|
||||
|
||||
Reference in New Issue
Block a user