/** * 自定义字段数据存储和读取工具 * * 功能: * - 将自定义字段key映射到Material模型的标准字段 * - 非标准字段存储到metadata JSON字段 * - 读取时合并标准字段和metadata数据 */ /** * Material模型的标准字段列表 * 这些字段直接存储在数据库列中 */ export const STANDARD_MATERIAL_FIELDS = [ 'productModel', 'brandName', 'seriesName', 'skuCode', 'materialTexture', 'categoryName', 'sceneName', 'materialType', 'materialKind', 'renderer', 'renderTime', 'imageResolution', 'colorMode', 'authorName', 'platformName', ] as const export type StandardMaterialField = typeof STANDARD_MATERIAL_FIELDS[number] /** * 检查字段key是否为标准字段 */ export function isStandardField(fieldKey: string): fieldKey is StandardMaterialField { return STANDARD_MATERIAL_FIELDS.includes(fieldKey as StandardMaterialField) } /** * 字段值类型 */ export type FieldValue = string | number | boolean | null | undefined /** * 分离标准字段和自定义字段 */ export function separateFieldValues( templateFields: Record ): { standardFields: Partial> customFields: Record } { const standardFields: Partial> = {} const customFields: Record = {} for (const [key, value] of Object.entries(templateFields)) { if (isStandardField(key)) { // 标准字段转换为字符串存储 standardFields[key] = value === null || value === undefined ? '' : String(value) } else { // 自定义字段保留原始类型 customFields[key] = value } } return { standardFields, customFields } } /** * 构建metadata JSON字符串 */ export function buildMetadata( customFields: Record, templateId?: string | null, previewUrls?: string[], existingMetadata?: string | null ): string | null { // 解析现有metadata let metadataObj: Record = {} if (existingMetadata) { try { metadataObj = JSON.parse(existingMetadata) } catch { // 忽略解析错误 } } // 更新templateId if (templateId) { metadataObj.templateId = templateId } // 更新自定义字段 if (Object.keys(customFields).length > 0) { metadataObj.templateFields = { ...(metadataObj.templateFields as Record || {}), ...customFields, } } // 更新预览图URLs if (previewUrls && previewUrls.length > 0) { metadataObj.previewUrls = previewUrls } // 如果没有任何数据,返回null if (Object.keys(metadataObj).length === 0) { return null } return JSON.stringify(metadataObj) } /** * 解析metadata JSON字符串 */ export function parseMetadata(metadata: string | null | undefined): { templateId?: string templateFields: Record previewUrls?: string[] } { if (!metadata) { return { templateFields: {} } } try { const parsed = JSON.parse(metadata) return { templateId: parsed.templateId, templateFields: parsed.templateFields || {}, previewUrls: parsed.previewUrls, } } catch { return { templateFields: {} } } } /** * 从Material记录中读取所有字段值(合并标准字段和metadata) */ export function readAllFieldValues( material: Record ): Record { const result: Record = {} // 读取标准字段 for (const field of STANDARD_MATERIAL_FIELDS) { const value = material[field] if (value !== undefined && value !== null && value !== '') { result[field] = value as FieldValue } } // 读取metadata中的自定义字段 const metadata = parseMetadata(material.metadata as string | null) for (const [key, value] of Object.entries(metadata.templateFields)) { // 自定义字段不覆盖标准字段 if (!isStandardField(key)) { result[key] = value } } return result } /** * 准备Material创建/更新数据 */ export function prepareMaterialData( templateFields: Record, templateId?: string | null, previewUrls?: string[], existingMetadata?: string | null ): { standardData: Partial> metadata: string | null } { const { standardFields, customFields } = separateFieldValues(templateFields) const metadata = buildMetadata(customFields, templateId, previewUrls, existingMetadata) return { standardData: standardFields, metadata, } } /** * 检查metadata大小是否超过限制 */ export function checkMetadataSize( metadata: string | null, maxSizeBytes: number = 65535 // 默认64KB,适合TEXT类型 ): { ok: boolean; size: number; maxSize: number } { const size = metadata ? new TextEncoder().encode(metadata).length : 0 return { ok: size <= maxSizeBytes, size, maxSize: maxSizeBytes, } } /** * 压缩metadata(移除空值和默认值) */ export function compressMetadata(metadata: string | null): string | null { if (!metadata) return null try { const parsed = JSON.parse(metadata) // 移除空的templateFields if (parsed.templateFields) { const cleanedFields: Record = {} for (const [key, value] of Object.entries(parsed.templateFields)) { if (value !== null && value !== undefined && value !== '') { cleanedFields[key] = value } } if (Object.keys(cleanedFields).length > 0) { parsed.templateFields = cleanedFields } else { delete parsed.templateFields } } // 移除空的previewUrls if (parsed.previewUrls && Array.isArray(parsed.previewUrls) && parsed.previewUrls.length === 0) { delete parsed.previewUrls } if (Object.keys(parsed).length === 0) { return null } return JSON.stringify(parsed) } catch { return metadata } } /** * 获取字段的存储位置 */ export function getFieldStorageLocation(fieldKey: string): 'standard' | 'metadata' { return isStandardField(fieldKey) ? 'standard' : 'metadata' } /** * 批量获取字段存储位置 */ export function getFieldsStorageLocations( fieldKeys: string[] ): Map { const result = new Map() for (const key of fieldKeys) { result.set(key, getFieldStorageLocation(key)) } return result }