ERP-node/frontend/lib/registry/components/v2-media/V2MediaRenderer.tsx

135 lines
4.2 KiB
TypeScript

"use client";
import React from "react";
import { AutoRegisteringComponentRenderer } from "../../AutoRegisteringComponentRenderer";
import { V2MediaDefinition } from "./index";
import { V2Media } from "@/components/v2/V2Media";
/**
* V2Media 렌더러
* 파일, 이미지, 비디오, 오디오 등 다양한 미디어 타입을 지원
* 자동 등록 시스템을 사용하여 컴포넌트를 레지스트리에 등록
*/
export class V2MediaRenderer extends AutoRegisteringComponentRenderer {
static componentDefinition = V2MediaDefinition;
render(): React.ReactElement {
const { component, formData, onFormDataChange, isDesignMode, isSelected, isInteractive, ...restProps } = this.props;
// 컴포넌트 설정 추출
const config = component.componentConfig || component.config || {};
const columnName = component.columnName;
const tableName = component.tableName || this.props.tableName;
// formData에서 현재 값 가져오기
const rawValue = formData?.[columnName] ?? component.value ?? "";
// objid를 미리보기 URL로 변환하는 함수 (number/string 모두 처리)
const convertToPreviewUrl = (val: any): string => {
if (val === null || val === undefined || val === "") return "";
// number면 string으로 변환
const strVal = String(val);
// 이미 URL 형태면 그대로 반환
if (strVal.startsWith("/") || strVal.startsWith("http")) return strVal;
// 숫자로만 이루어진 문자열이면 objid로 간주하고 미리보기 URL 생성
if (/^\d+$/.test(strVal)) {
return `/api/files/preview/${strVal}`;
}
return strVal;
};
// 배열 또는 단일 값 처리
const currentValue = Array.isArray(rawValue)
? rawValue.map(convertToPreviewUrl)
: convertToPreviewUrl(rawValue);
console.log("[V2Media] rawValue:", rawValue, "-> currentValue:", currentValue);
// 값 변경 핸들러
const handleChange = (value: any) => {
if (isInteractive && onFormDataChange && columnName) {
onFormDataChange(columnName, value);
}
};
// V1 file-upload, image-widget에서 넘어온 설정 매핑
const mediaType = config.mediaType || config.type || this.getMediaTypeFromWebType(component.webType);
// maxSize: MB → bytes 변환 (V1은 bytes, V2는 MB 단위 사용)
const maxSizeBytes = config.maxSize
? (config.maxSize > 1000 ? config.maxSize : config.maxSize * 1024 * 1024)
: 10 * 1024 * 1024; // 기본 10MB
return (
<V2Media
id={component.id}
label={component.label}
required={component.required}
readonly={config.readonly || component.readonly}
disabled={config.disabled || component.disabled}
value={currentValue}
onChange={handleChange}
config={{
type: mediaType,
multiple: config.multiple ?? false,
preview: config.preview ?? true,
maxSize: maxSizeBytes,
accept: config.accept || this.getDefaultAccept(mediaType),
uploadEndpoint: config.uploadEndpoint || "/files/upload",
}}
style={component.style}
size={component.size}
formData={formData}
columnName={columnName}
tableName={tableName}
{...restProps}
/>
);
}
/**
* webType에서 미디어 타입 추출
*/
private getMediaTypeFromWebType(webType?: string): "file" | "image" | "video" | "audio" {
switch (webType) {
case "image":
return "image";
case "video":
return "video";
case "audio":
return "audio";
case "file":
default:
return "file";
}
}
/**
* 미디어 타입에 따른 기본 accept 값
*/
private getDefaultAccept(mediaType: string): string {
switch (mediaType) {
case "image":
return "image/*";
case "video":
return "video/*";
case "audio":
return "audio/*";
default:
return "*/*";
}
}
}
// 자동 등록 실행
V2MediaRenderer.registerSelf();
// Hot Reload 지원 (개발 모드)
if (process.env.NODE_ENV === "development") {
V2MediaRenderer.enableHotReload();
}