Files
xiaoxia-saas/apps/web/src/pages/templates/utils/templateLibrary.ts
T
xiaoxia bb56094029
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 12s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m13s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m15s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 1m30s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 51s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 2m11s
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 35s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 46s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m22s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 2m21s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 52s
AI Code Review / AI Code Review (pull_request) Successful in 1m36s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 17s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 1247h13m47s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 1247h15m29s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1247h15m33s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 1247h15m46s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 1247h18m5s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1247h18m5s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 1247h21m40s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 1247h21m41s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 1247h21m41s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 1247h21m42s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 1247h26m12s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 1247h26m16s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1247h48m9s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 1247h58m53s
refactor(template-library): 三阶段重构 TemplateLibrary(716→107行, -85%)
Phase 1 - 抽类型/常量/工具函数:
- types/templateLibrary.ts: EditTemplateType, DurationRange, ConfigDisplayFields
- constants/templateLibrary.ts: TEMPLATE_TYPES, DURATION_OPTIONS, MATERIAL_TYPE_LABELS, 渐变色映射
- utils/templateLibrary.ts: getTypeColor, gradientForCategory, formatDuration, formatConfig, getMaterialTypeLabel, calcTotalSegmentDuration

Phase 2 - 抽 5 个 UI 组件:
- TemplateCard: 模板卡片(缩略图+信息+操作按钮)
- TemplateDetailModal: 模板详情弹窗(预览+素材规则+样式配置)
- TemplateHeader: 页面头部(标题+创建按钮)
- TemplateToolbar: 工具栏(搜索+分类+时长筛选)
- TemplateGrid: 模板网格 + 空状态 + 分页 + Loading/Error

Phase 3 - 抽 2 个业务 Hook:
- useTemplateLibrary: 数据获取、筛选、分页、收藏/复制 mutations
- useTemplateDetail: 详情弹窗逻辑(预览加载、收藏乐观更新)

主文件 716→107 行,共新增 10 个文件
2026-07-26 15:56:44 +08:00

55 lines
2.0 KiB
TypeScript

import type { ConfigDisplayFields } from "../types/templateLibrary"
import {
TEMPLATE_TYPES,
CATEGORY_GRADIENT_MAP,
DEFAULT_GRADIENT,
MATERIAL_TYPE_LABELS,
} from "../constants/templateLibrary"
import type { TemplateSegment } from "@/api/templates"
/** 获取类型对应颜色 */
export const getTypeColor = (type: string): string => {
const found = TEMPLATE_TYPES.find((t) => t.type === type)
return found?.color ?? "#6366f1"
}
/** 根据 category 生成占位渐变色 */
export const gradientForCategory = (category: string): string => {
return CATEGORY_GRADIENT_MAP[category] ?? DEFAULT_GRADIENT
}
/** 格式化时长 */
export const formatDuration = (seconds: number | undefined | null): string => {
if (!seconds || seconds <= 0) return "0秒"
const totalSec = Math.round(seconds)
const m = Math.floor(totalSec / 60)
const s = totalSec % 60
if (m === 0) return `${s}秒`
return `${m}分${s > 0 ? `${s}秒` : ""}`
}
/** 格式化配置对象为可读文本 */
export const formatConfig = (config?: object): string => {
if (!config || Object.keys(config).length === 0) return "默认"
const c = config as ConfigDisplayFields
const parts: string[] = []
if (c.font_size) parts.push(`字号: ${c.font_size}`)
if (c.font_family) parts.push(`字体: ${c.font_family}`)
if (c.color) parts.push(`颜色: ${c.color}`)
if (c.position) parts.push(`位置: ${c.position}`)
if (c.volume !== undefined) parts.push(`音量: ${c.volume}%`)
if (c.name) parts.push(String(c.name))
return parts.length > 0 ? parts.join(" / ") : JSON.stringify(config)
}
/** 获取素材类型标签文本 */
export const getMaterialTypeLabel = (materialType: string | null | undefined): string => {
if (!materialType) return "不限"
return MATERIAL_TYPE_LABELS[materialType] ?? materialType
}
/** 计算片段总时长(取每个片段 min/max 的平均值) */
export const calcTotalSegmentDuration = (segments: TemplateSegment[]): number => {
return segments.reduce((sum, s) => sum + (s.duration_min + s.duration_max) / 2, 0)
}