import { useEffect, useState } from 'react' import { Link, useParams } from 'react-router-dom' import { Helmet } from 'react-helmet-async' import type { TemplateDetailStats } from '../../../services/api/contracts' import { getTemplateBasicInfo, getTemplateStats, getTemplateUsageResults, type TemplateBasicInfo, type TemplateUsageResult, } from '../../../services/api/templates' import { usePageContext } from '../../../shared/pageContext' import { DashboardLayout } from '../../../layouts/DashboardLayout' const FALLBACK_PAGE_COPY = { title: '发型模板详情', description: '查看模板封面、基本信息与使用情况。', back: '返回发型模板列表', badge: '模板详情', lead: '确认模板封面、基础信息和顾客使用结果。', preview: { badge: '预览', title: '模板预览', imageAlt: '模板封面', }, info: { badge: '模板信息', title: '发型模板基本信息', name: '模板名称', status: '状态', category: '分类', tags: '标签', description: '说明', }, stats: { customers: '使用顾客数', saveRate: '提案后保存率', monthlyGenerated: '本月生成次数', }, results: { badge: '顾客生成结果', title: '使用该模板的顾客', action: '查看全部', empty: '暂无顾客生成结果', }, states: { loading: '正在加载模板详情...', notFound: '模板不存在或已删除', }, statusOptions: { DRAFT: '草稿', PUBLIC: '公开中', }, categoryOptions: { LONG: '长发', MEDIUM: '中长发', SHORT: '短发', DYE: '染发', }, } as const function renderValue(value?: string) { return value && value.trim() ? value : '-' } export function TemplateDetailPage() { const { locale, path, copy } = usePageContext() const params = useParams<{ templateId: string }>() const pageCopy = copy.templateDetailPage ?? FALLBACK_PAGE_COPY const [template, setTemplate] = useState(null) const [loading, setLoading] = useState(true) const [notFound, setNotFound] = useState(false) const [usageResults, setUsageResults] = useState([]) const [stats, setStats] = useState({ customerCount: 0, saveRate: 0, monthlyGeneratedCount: 0, }) useEffect(() => { let cancelled = false const load = async () => { if (!params.templateId) { setNotFound(true) setLoading(false) return } setLoading(true) setNotFound(false) try { const [templateData, statsData, usageData] = await Promise.all([ getTemplateBasicInfo(params.templateId), getTemplateStats(params.templateId).catch(() => ({ customerCount: 0, saveRate: 0, monthlyGeneratedCount: 0, })), getTemplateUsageResults(params.templateId).catch(() => []), ]) if (cancelled) return setTemplate(templateData) setStats(statsData) setUsageResults(usageData) } catch { if (!cancelled) { setTemplate(null) setNotFound(true) } } finally { if (!cancelled) { setLoading(false) } } } void load() return () => { cancelled = true } }, [params.templateId]) if (loading) { return (

{pageCopy.states.loading}

) } if (notFound || !template) { return (

{pageCopy.states.notFound}

) } return ( {`Aitori Stylist | ${pageCopy.title}`}
{pageCopy.back} {copy.common.edit}
{pageCopy.badge}

{pageCopy.title}

{pageCopy.lead}

{pageCopy.preview.badge}

{pageCopy.preview.title}

{pageCopy.statusOptions[template.status] ?? template.status}
{pageCopy.preview.imageAlt}
{pageCopy.info.badge}

{pageCopy.info.title}

{pageCopy.info.name}
{renderValue(template.templateName)}
{pageCopy.info.status}
{pageCopy.statusOptions[template.status] ?? template.status}
{pageCopy.info.category}
{pageCopy.categoryOptions[template.category] ?? template.category}
{pageCopy.info.tags}
{renderValue(template.tags.join(', '))}
{pageCopy.info.description}
{renderValue(template.description)}
{stats.customerCount} {pageCopy.stats.customers}
{stats.saveRate}% {pageCopy.stats.saveRate}
{stats.monthlyGeneratedCount} {pageCopy.stats.monthlyGenerated}
{pageCopy.results.badge}

{pageCopy.results.title}

{pageCopy.results.action}
{usageResults.length === 0 ? (

{pageCopy.results.empty}

) : (
{usageResults.map((item, index) => (
{item.beforeImage ? before : null} {item.afterImage ? after : null}
{item.status} {item.date}

{item.note}

))}
)}
) }