diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts new file mode 100644 index 0000000..bcb71cc --- /dev/null +++ b/src/hooks/useAuth.ts @@ -0,0 +1,19 @@ +/** + * 认证状态 Hook + */ + +import { useMemo } from 'react' + +export const useAuth = () => { + // 检查本地存储中是否有 token + const token = localStorage.getItem('hrt-token') + + const isAuthenticated = useMemo(() => { + return !!token + }, [token]) + + return { + isAuthenticated, + token, + } +} diff --git a/src/utils/heritageTransform.ts b/src/utils/heritageTransform.ts new file mode 100644 index 0000000..4f02c0a --- /dev/null +++ b/src/utils/heritageTransform.ts @@ -0,0 +1,81 @@ +/** + * 非遗数据转换工具 + * 将后端返回的数据格式转换为前端使用的格式 + */ + +import type { HeritageListItem, HeritageDetail, HeritageItem } from '@/types' + +/** + * 将后端列表项转换为前端HeritageItem格式 + */ +export const transformHeritageListItem = (item: HeritageListItem): HeritageItem => { + // 解析tags字符串为数组 + const tagsArray = item.tags ? item.tags.split(',').map(t => t.trim()).filter(Boolean) : [] + + return { + id: String(item.id), + name: item.name, + category: item.category as any, // 后端返回的category格式应该与前端一致 + province: item.province, + city: item.city, + level: item.level as any, + coverImage: item.coverImage, + description: item.description, + // 以下字段列表接口没有,使用默认值 + history: '', + skills: '', + significance: '', + inheritors: [], + videoUrl: '', + virtualTourUrl: '', + status: item.status as 'active' | 'endangered' | 'revived', + tags: tagsArray, + viewCount: item.viewCount || 0, + likeCount: item.likeCount || 0, + createdAt: item.createTime, + updatedAt: item.createTime, + } +} + +/** + * 将后端详情数据转换为前端HeritageItem格式 + */ +export const transformHeritageDetail = (detail: HeritageDetail): HeritageItem => { + // 解析tags字符串为数组 + const tagsArray = detail.tags ? detail.tags.split(',').map(t => t.trim()).filter(Boolean) : [] + + // 解析images JSON字符串为数组 + let imagesArray: string[] = [] + try { + if (detail.images) { + imagesArray = JSON.parse(detail.images) + } + } catch (error) { + console.error('Failed to parse images JSON:', error) + imagesArray = [] + } + + return { + id: String(detail.id), + name: detail.name, + category: detail.category as any, + province: detail.province, + city: detail.city, + level: detail.level as any, + coverImage: detail.coverImage, + images: imagesArray, + description: detail.description, + history: detail.history || '', + skills: detail.skills || '', + significance: detail.significance || '', + inheritors: [], // 传承人信息需要另外接口获取 + videoUrl: detail.videoUrl, + virtualTourUrl: '', + status: detail.status as 'active' | 'endangered' | 'revived', + tags: tagsArray, + viewCount: detail.viewCount || 0, + likeCount: detail.likeCount || 0, + createdAt: detail.createTime, + updatedAt: detail.updateTime, + } +} diff --git a/src/utils/inheritorTransform.ts b/src/utils/inheritorTransform.ts new file mode 100644 index 0000000..57642b7 --- /dev/null +++ b/src/utils/inheritorTransform.ts @@ -0,0 +1,125 @@ +/** + * 传承人数据转换工具 + * 将后端返回的数据格式转换为前端使用的格式 + */ + +import type { InheritorListItem, InheritorDetail, Inheritor } from '@/types' + +/** + * 将后端列表项转换为前端Inheritor格式 + */ +export const transformInheritorListItem = (item: InheritorListItem): Inheritor => { + // 计算年龄 + const currentYear = new Date().getFullYear() + const age = currentYear - item.birthYear + + return { + id: String(item.id), + name: item.name, + avatar: item.avatar, + coverImage: item.avatar, // 使用头像作为封面 + gender: item.gender === 1 ? 'male' : 'female', + birthYear: item.birthYear, + province: item.province, + city: item.city, + level: item.level as any, + heritageItems: [String(item.heritageId)], + title: `${getLevelLabel(item.level)}代表性传承人`, + bio: item.introduction || '', + masterSkills: item.heritageName || '', + achievements: [], + awards: [], + works: [], + videos: [], + followers: item.likeCount || 0, + viewCount: item.viewCount || 0, + createdAt: item.createTime, + updatedAt: item.createTime, + } +} + +/** + * 将后端详情数据转换为前端Inheritor格式 + */ +export const transformInheritorDetail = (detail: InheritorDetail): Inheritor => { + // 计算年龄 + const currentYear = new Date().getFullYear() + const age = currentYear - detail.birthYear + + // 解析works JSON字符串为数组 + let worksArray: any[] = [] + try { + if (detail.works) { + worksArray = JSON.parse(detail.works) + } + } catch (error) { + console.error('Failed to parse works JSON:', error) + } + + // 解析images JSON字符串为数组 + let imagesArray: string[] = [] + try { + if (detail.images) { + imagesArray = JSON.parse(detail.images) + } + } catch (error) { + console.error('Failed to parse images JSON:', error) + } + + return { + id: String(detail.id), + name: detail.name, + avatar: detail.avatar, + coverImage: imagesArray[0] || detail.avatar, + gender: detail.gender === 1 ? 'male' : 'female', + birthYear: detail.birthYear, + province: detail.province, + city: detail.city, + level: detail.level as any, + heritageItems: [String(detail.heritageId)], + title: `${getLevelLabel(detail.level)}代表性传承人`, + bio: detail.introduction || '', + masterSkills: detail.heritageName || '', + achievements: detail.achievements ? parseAchievements(detail.achievements) : [], + awards: [], + works: worksArray, + videos: detail.videoUrl ? [{ + id: 'video-1', + title: `${detail.name}的传承故事`, + cover: detail.avatar, + url: detail.videoUrl, + duration: 0, + viewCount: 0, + publishDate: detail.createTime, + }] : [], + followers: detail.likeCount || 0, + viewCount: detail.viewCount || 0, + createdAt: detail.createTime, + updatedAt: detail.updateTime, + } +} + +/** + * 获取级别标签 + */ +function getLevelLabel(level: string): string { + const levelMap: Record = { + national: '国家级', + provincial: '省级', + municipal: '市级', + } + return levelMap[level] || level +} + +/** + * 解析成就文本为数组 + */ +function parseAchievements(achievements: string): any[] { + // 简单按换行分割 + return achievements.split('\n').filter(Boolean).map((text, index) => ({ + id: `achievement-${index}`, + title: text.trim(), + description: '', + date: '', + })) +}