/** * 卡片类型注册表 * * 新增卡片类型只需在此文件中: * 1. 在 CardTypes 数组中添加类型值 * 2. 在 cardTypeRegistry 中添加对应配置 * 3. 创建对应的瀑布流渲染组件 * * 无需修改 index.vue / CardFormModal / CardDetailModal。 */ import type { Component } from 'vue' import WaterfallCard from '~/components/index/WaterfallCard.vue' import WaterfallTextCard from '~/components/index/WaterfallTextCard.vue' import WaterfallImageCard from '~/components/index/WaterfallImageCard.vue' import WaterfallPortfolioCard from '~/components/index/WaterfallPortfolioCard.vue' import WaterfallProjectCard from '~/components/index/WaterfallProjectCard.vue' // ============ CardType 常量(与 drizzle schema 保持同步) ============ export const CardTypes = [ 'text', 'image', 'image-text', 'portfolio', 'project', ] as const export type CardType = (typeof CardTypes)[number] // ============ 前端卡片数据接口 ============ export interface CardItemLike { id?: number type: CardType image?: string images?: string[] title: string description?: string tags?: string[] aspectRatio: number categoryId?: string | null createdAt?: string } // ============ 类型配置 ============ export interface CardTypeFormFields { /** 是否需要单张图片 */ image?: boolean /** 是否需要多张图片 */ multiImage?: boolean /** 是否需要描述字段 */ description?: boolean /** 是否需要标签选择 */ tags?: boolean } export interface CardTypeConfig { /** 瀑布流渲染组件 */ component: Component /** 中文标签 */ label: string /** 图标名 (lucide:xxx) */ icon: string /** 表单字段需求 */ formFields: CardTypeFormFields /** 从 CardItemLike 提取该组件需要的 props */ mapProps: (item: CardItemLike) => Record } // ============ 注册表 ============ export const cardTypeRegistry: Record = { text: { component: WaterfallTextCard, label: '纯文本', icon: 'lucide:text', formFields: { description: true }, mapProps: (item) => ({ title: item.title, description: item.description ?? '', aspectRatio: item.aspectRatio, }), }, image: { component: WaterfallImageCard, label: '图片', icon: 'lucide:image', formFields: { image: true }, mapProps: (item) => ({ image: item.image ?? '', title: item.title, aspectRatio: item.aspectRatio, }), }, 'image-text': { component: WaterfallCard, label: '图文', icon: 'lucide:image-plus', formFields: { image: true, description: true }, mapProps: (item) => ({ image: item.image ?? '', title: item.title, description: item.description ?? '', aspectRatio: item.aspectRatio, }), }, portfolio: { component: WaterfallPortfolioCard, label: '图集', icon: 'lucide:layout-grid', formFields: { multiImage: true, description: true }, mapProps: (item) => ({ images: item.images ?? [], title: item.title, description: item.description ?? '', aspectRatio: item.aspectRatio, }), }, project: { component: WaterfallProjectCard, label: '项目', icon: 'lucide:folder-kanban', formFields: { image: true, description: true, tags: true }, mapProps: (item) => ({ image: item.image ?? '', title: item.title, description: item.description ?? '', tags: item.tags ?? [], aspectRatio: item.aspectRatio, }), }, } // ============ 派生数据(供表单等使用) ============ /** 类型选项列表(用于表单类型选择器) */ export const CARD_TYPE_OPTIONS = CardTypes.map((t) => ({ value: t, label: cardTypeRegistry[t].label, icon: cardTypeRegistry[t].icon, })) /** 获取类型中文标签 */ export function getTypeLabel(type: CardType | string): string { return cardTypeRegistry[type as CardType]?.label ?? type } /** * 运行时校验:确保注册表覆盖了所有 CardType * 如果注册表缺少某个类型,会在控制台警告 */ if (import.meta.dev) { for (const t of CardTypes) { if (!cardTypeRegistry[t]) { console.warn(`[cardTypes] 注册表缺少类型 "${t}" 的配置`) } } }