添加类型定义、主题配置和状态管理
- 定义核心数据类型(HeritageItem、Inheritor、NewsArticle、Event等) - 配置Ant Design主题色和组件样式 - 添加用户状态管理(Zustand)
This commit is contained in:
parent
7abc7becee
commit
cb195382eb
129
src/store/useUserStore.ts
Normal file
129
src/store/useUserStore.ts
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 用户状态管理 - Zustand Store
|
||||
*/
|
||||
|
||||
import { create } from 'zustand'
|
||||
import { persist } from 'zustand/middleware'
|
||||
import type { User } from '@types/index'
|
||||
import { login as apiLogin, getUserById } from '@services/api'
|
||||
|
||||
interface UserState {
|
||||
user: User | null
|
||||
isAuthenticated: boolean
|
||||
isLoading: boolean
|
||||
|
||||
// Actions
|
||||
login: (username: string, password: string) => Promise<boolean>
|
||||
logout: () => void
|
||||
updateUser: (userData: Partial<User>) => void
|
||||
addFavorite: (heritageId: string) => void
|
||||
removeFavorite: (heritageId: string) => void
|
||||
followInheritor: (inheritorId: string) => void
|
||||
unfollowInheritor: (inheritorId: string) => void
|
||||
enrollCourse: (courseId: string) => void
|
||||
}
|
||||
|
||||
export const useUserStore = create<UserState>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
user: null,
|
||||
isAuthenticated: false,
|
||||
isLoading: false,
|
||||
|
||||
login: async (username: string, password: string) => {
|
||||
set({ isLoading: true })
|
||||
try {
|
||||
const user = await apiLogin(username, password)
|
||||
if (user) {
|
||||
set({ user, isAuthenticated: true, isLoading: false })
|
||||
return true
|
||||
}
|
||||
set({ isLoading: false })
|
||||
return false
|
||||
} catch (error) {
|
||||
console.error('Login failed:', error)
|
||||
set({ isLoading: false })
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
logout: () => {
|
||||
set({ user: null, isAuthenticated: false })
|
||||
},
|
||||
|
||||
updateUser: (userData: Partial<User>) => {
|
||||
const { user } = get()
|
||||
if (user) {
|
||||
set({ user: { ...user, ...userData } })
|
||||
}
|
||||
},
|
||||
|
||||
addFavorite: (heritageId: string) => {
|
||||
const { user } = get()
|
||||
if (user && !user.favorites.includes(heritageId)) {
|
||||
set({
|
||||
user: {
|
||||
...user,
|
||||
favorites: [...user.favorites, heritageId],
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
removeFavorite: (heritageId: string) => {
|
||||
const { user } = get()
|
||||
if (user) {
|
||||
set({
|
||||
user: {
|
||||
...user,
|
||||
favorites: user.favorites.filter((id) => id !== heritageId),
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
followInheritor: (inheritorId: string) => {
|
||||
const { user } = get()
|
||||
if (user && !user.followedInheritors.includes(inheritorId)) {
|
||||
set({
|
||||
user: {
|
||||
...user,
|
||||
followedInheritors: [...user.followedInheritors, inheritorId],
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
unfollowInheritor: (inheritorId: string) => {
|
||||
const { user } = get()
|
||||
if (user) {
|
||||
set({
|
||||
user: {
|
||||
...user,
|
||||
followedInheritors: user.followedInheritors.filter((id) => id !== inheritorId),
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
enrollCourse: (courseId: string) => {
|
||||
const { user } = get()
|
||||
if (user && !user.enrolledCourses.includes(courseId)) {
|
||||
set({
|
||||
user: {
|
||||
...user,
|
||||
enrolledCourses: [...user.enrolledCourses, courseId],
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'user-storage', // localStorage key
|
||||
partialize: (state) => ({
|
||||
user: state.user,
|
||||
isAuthenticated: state.isAuthenticated,
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
384
src/theme/components.ts
Normal file
384
src/theme/components.ts
Normal file
@ -0,0 +1,384 @@
|
||||
/**
|
||||
* 非遗文化传承网站 - 组件级主题定制
|
||||
* 覆盖 Ant Design 全组件族的样式
|
||||
*/
|
||||
|
||||
export const componentTokens = {
|
||||
// ===== 通用组件 =====
|
||||
Button: {
|
||||
colorPrimary: '#C8363D',
|
||||
colorPrimaryHover: '#A82E34',
|
||||
colorPrimaryActive: '#8B252B',
|
||||
primaryShadow: '0 2px 0 rgba(200, 54, 61, 0.1)',
|
||||
defaultShadow: '0 2px 0 rgba(0, 0, 0, 0.02)',
|
||||
controlHeight: 40,
|
||||
controlHeightLG: 48,
|
||||
controlHeightSM: 32,
|
||||
borderRadius: 8,
|
||||
borderRadiusLG: 12,
|
||||
borderRadiusSM: 6,
|
||||
fontWeight: 500,
|
||||
},
|
||||
|
||||
FloatButton: {
|
||||
colorPrimary: '#C8363D',
|
||||
colorPrimaryHover: '#A82E34',
|
||||
boxShadow: '0 4px 16px rgba(200, 54, 61, 0.15)',
|
||||
},
|
||||
|
||||
Typography: {
|
||||
colorTextHeading: '#2C2C2C',
|
||||
colorText: '#2C2C2C',
|
||||
fontSizeHeading1: 38,
|
||||
fontSizeHeading2: 30,
|
||||
fontSizeHeading3: 24,
|
||||
fontSizeHeading4: 20,
|
||||
fontSizeHeading5: 16,
|
||||
fontWeightStrong: 600,
|
||||
},
|
||||
|
||||
// ===== 布局组件 =====
|
||||
Layout: {
|
||||
headerBg: '#FFFFFF',
|
||||
headerHeight: 64,
|
||||
headerPadding: '0 50px',
|
||||
footerBg: '#2C2C2C',
|
||||
footerPadding: '48px 50px',
|
||||
bodyBg: '#FAFAF8',
|
||||
siderBg: '#FFFFFF',
|
||||
},
|
||||
|
||||
Divider: {
|
||||
colorSplit: '#E8E3DB',
|
||||
marginLG: 24,
|
||||
},
|
||||
|
||||
Space: {
|
||||
marginXS: 8,
|
||||
marginSM: 12,
|
||||
marginMD: 16,
|
||||
marginLG: 24,
|
||||
marginXL: 32,
|
||||
},
|
||||
|
||||
// ===== 导航组件 =====
|
||||
Menu: {
|
||||
itemBg: 'transparent',
|
||||
itemColor: '#666666',
|
||||
itemSelectedBg: 'rgba(200, 54, 61, 0.08)',
|
||||
itemSelectedColor: '#C8363D',
|
||||
itemHoverBg: 'rgba(200, 54, 61, 0.05)',
|
||||
itemHoverColor: '#C8363D',
|
||||
itemActiveBg: 'rgba(200, 54, 61, 0.1)',
|
||||
itemHeight: 48,
|
||||
itemBorderRadius: 8,
|
||||
iconSize: 18,
|
||||
fontSize: 14,
|
||||
},
|
||||
|
||||
Breadcrumb: {
|
||||
linkColor: '#666666',
|
||||
linkHoverColor: '#C8363D',
|
||||
lastItemColor: '#2C2C2C',
|
||||
fontSize: 14,
|
||||
},
|
||||
|
||||
Pagination: {
|
||||
itemActiveBg: '#C8363D',
|
||||
itemActiveColorDisabled: '#FFFFFF',
|
||||
colorPrimary: '#C8363D',
|
||||
colorPrimaryHover: '#A82E34',
|
||||
itemLinkBg: '#FFFFFF',
|
||||
itemBg: '#FFFFFF',
|
||||
borderRadius: 8,
|
||||
colorText: '#1a1a1a',
|
||||
colorTextDisabled: '#d9d9d9',
|
||||
},
|
||||
|
||||
Tabs: {
|
||||
itemColor: '#666666',
|
||||
itemSelectedColor: '#C8363D',
|
||||
itemHoverColor: '#C8363D',
|
||||
itemActiveColor: '#C8363D',
|
||||
inkBarColor: '#C8363D',
|
||||
cardBg: '#F5F0E8',
|
||||
cardPadding: '12px 16px',
|
||||
titleFontSize: 16,
|
||||
},
|
||||
|
||||
Steps: {
|
||||
finishIconBorderColor: '#C8363D',
|
||||
colorPrimary: '#C8363D',
|
||||
},
|
||||
|
||||
// ===== 数据录入组件 =====
|
||||
Input: {
|
||||
borderRadius: 8,
|
||||
controlHeight: 40,
|
||||
controlHeightLG: 48,
|
||||
controlHeightSM: 32,
|
||||
colorBorder: '#E8E3DB',
|
||||
colorBgContainer: '#FFFFFF',
|
||||
colorTextPlaceholder: '#CCCCCC',
|
||||
activeBorderColor: '#C8363D',
|
||||
hoverBorderColor: '#C8363D',
|
||||
activeShadow: '0 0 0 2px rgba(200, 54, 61, 0.1)',
|
||||
},
|
||||
|
||||
InputNumber: {
|
||||
borderRadius: 8,
|
||||
controlHeight: 40,
|
||||
handleVisible: true,
|
||||
},
|
||||
|
||||
Select: {
|
||||
borderRadius: 8,
|
||||
controlHeight: 40,
|
||||
optionSelectedBg: 'rgba(200, 54, 61, 0.08)',
|
||||
optionActiveBg: 'rgba(200, 54, 61, 0.05)',
|
||||
optionSelectedColor: '#C8363D',
|
||||
},
|
||||
|
||||
Checkbox: {
|
||||
borderRadiusSM: 4,
|
||||
colorPrimary: '#C8363D',
|
||||
colorPrimaryHover: '#A82E34',
|
||||
},
|
||||
|
||||
Radio: {
|
||||
colorPrimary: '#C8363D',
|
||||
dotSize: 10,
|
||||
},
|
||||
|
||||
Switch: {
|
||||
colorPrimary: '#C8363D',
|
||||
colorPrimaryHover: '#A82E34',
|
||||
},
|
||||
|
||||
Slider: {
|
||||
trackBg: '#C8363D',
|
||||
trackHoverBg: '#A82E34',
|
||||
handleColor: '#C8363D',
|
||||
handleActiveColor: '#8B252B',
|
||||
dotBorderColor: '#E8E3DB',
|
||||
dotActiveBorderColor: '#C8363D',
|
||||
},
|
||||
|
||||
DatePicker: {
|
||||
borderRadius: 8,
|
||||
controlHeight: 40,
|
||||
cellActiveWithRangeBg: 'rgba(200, 54, 61, 0.1)',
|
||||
cellHoverBg: 'rgba(200, 54, 61, 0.05)',
|
||||
},
|
||||
|
||||
Rate: {
|
||||
colorFillContent: '#E8E3DB',
|
||||
starColor: '#D4A574',
|
||||
starSize: 20,
|
||||
},
|
||||
|
||||
Form: {
|
||||
labelColor: '#2C2C2C',
|
||||
labelFontSize: 14,
|
||||
labelHeight: 32,
|
||||
labelRequiredMarkColor: '#FF4D4F',
|
||||
itemMarginBottom: 24,
|
||||
},
|
||||
|
||||
Upload: {
|
||||
colorBorder: '#E8E3DB',
|
||||
colorBorderHover: '#C8363D',
|
||||
colorPrimary: '#C8363D',
|
||||
},
|
||||
|
||||
// ===== 数据展示组件 =====
|
||||
Card: {
|
||||
borderRadiusLG: 12,
|
||||
boxShadowTertiary: '0 2px 12px rgba(0, 0, 0, 0.08)',
|
||||
headerBg: '#FFFFFF',
|
||||
headerFontSize: 16,
|
||||
headerHeight: 48,
|
||||
paddingLG: 24,
|
||||
colorBorderSecondary: '#E8E3DB',
|
||||
},
|
||||
|
||||
Carousel: {
|
||||
dotHeight: 8,
|
||||
dotWidth: 24,
|
||||
dotWidthActive: 32,
|
||||
dotGap: 8,
|
||||
},
|
||||
|
||||
Collapse: {
|
||||
headerBg: '#F5F0E8',
|
||||
headerPadding: '12px 16px',
|
||||
contentBg: '#FFFFFF',
|
||||
contentPadding: '16px',
|
||||
borderRadiusLG: 12,
|
||||
},
|
||||
|
||||
Descriptions: {
|
||||
labelBg: '#F5F0E8',
|
||||
titleColor: '#2C2C2C',
|
||||
contentColor: '#666666',
|
||||
itemPaddingBottom: 16,
|
||||
},
|
||||
|
||||
Empty: {
|
||||
colorTextDescription: '#999999',
|
||||
fontSize: 14,
|
||||
},
|
||||
|
||||
Image: {
|
||||
previewOperationColor: '#FFFFFF',
|
||||
previewOperationColorDisabled: 'rgba(255, 255, 255, 0.3)',
|
||||
},
|
||||
|
||||
List: {
|
||||
itemPadding: '12px 0',
|
||||
itemPaddingSM: '8px 16px',
|
||||
itemPaddingLG: '16px 24px',
|
||||
},
|
||||
|
||||
Table: {
|
||||
headerBg: '#F5F0E8',
|
||||
headerColor: '#2C2C2C',
|
||||
rowHoverBg: '#FFF9F0',
|
||||
rowSelectedBg: 'rgba(200, 54, 61, 0.05)',
|
||||
rowSelectedHoverBg: 'rgba(200, 54, 61, 0.08)',
|
||||
borderColor: '#E8E3DB',
|
||||
headerSplitColor: '#E8E3DB',
|
||||
borderRadius: 12,
|
||||
cellPaddingBlock: 16,
|
||||
cellFontSize: 14,
|
||||
},
|
||||
|
||||
Tag: {
|
||||
defaultBg: '#F5F0E8',
|
||||
defaultColor: '#666666',
|
||||
borderRadiusSM: 6,
|
||||
fontSizeSM: 12,
|
||||
},
|
||||
|
||||
Timeline: {
|
||||
dotBorderWidth: 2,
|
||||
dotBg: '#FFFFFF',
|
||||
tailColor: '#E8E3DB',
|
||||
tailWidth: 2,
|
||||
},
|
||||
|
||||
Tooltip: {
|
||||
colorBgSpotlight: 'rgba(44, 44, 44, 0.9)',
|
||||
borderRadius: 8,
|
||||
},
|
||||
|
||||
Statistic: {
|
||||
titleFontSize: 14,
|
||||
contentFontSize: 24,
|
||||
fontFamily: 'monospace',
|
||||
},
|
||||
|
||||
Badge: {
|
||||
colorError: '#C8363D',
|
||||
dotSize: 8,
|
||||
statusSize: 8,
|
||||
},
|
||||
|
||||
Avatar: {
|
||||
borderRadius: 8,
|
||||
containerSize: 40,
|
||||
containerSizeLG: 48,
|
||||
containerSizeSM: 32,
|
||||
},
|
||||
|
||||
// ===== 反馈组件 =====
|
||||
Alert: {
|
||||
borderRadiusLG: 12,
|
||||
colorInfoBg: '#E6F7FF',
|
||||
colorSuccessBg: '#F6FFED',
|
||||
colorWarningBg: '#FFFBE6',
|
||||
colorErrorBg: '#FFF1F0',
|
||||
defaultPadding: '12px 16px',
|
||||
},
|
||||
|
||||
Modal: {
|
||||
headerBg: '#FFFFFF',
|
||||
contentBg: '#FFFFFF',
|
||||
footerBg: '#FFFFFF',
|
||||
borderRadiusLG: 12,
|
||||
boxShadow: '0 6px 48px rgba(0, 0, 0, 0.12)',
|
||||
titleColor: '#2C2C2C',
|
||||
titleFontSize: 18,
|
||||
},
|
||||
|
||||
Drawer: {
|
||||
colorBgElevated: '#FFFFFF',
|
||||
paddingLG: 24,
|
||||
footerPaddingBlock: 12,
|
||||
footerPaddingInline: 16,
|
||||
},
|
||||
|
||||
Message: {
|
||||
contentBg: 'rgba(44, 44, 44, 0.9)',
|
||||
contentPadding: '10px 16px',
|
||||
borderRadiusLG: 8,
|
||||
},
|
||||
|
||||
Notification: {
|
||||
width: 384,
|
||||
borderRadiusLG: 12,
|
||||
boxShadow: '0 6px 24px rgba(0, 0, 0, 0.12)',
|
||||
paddingContentHorizontal: 24,
|
||||
paddingContentVertical: 16,
|
||||
},
|
||||
|
||||
Progress: {
|
||||
defaultColor: '#C8363D',
|
||||
circleTextColor: '#2C2C2C',
|
||||
remainingColor: '#F5F0E8',
|
||||
},
|
||||
|
||||
Result: {
|
||||
titleFontSize: 24,
|
||||
subtitleFontSize: 14,
|
||||
iconFontSize: 72,
|
||||
},
|
||||
|
||||
Skeleton: {
|
||||
color: '#F5F0E8',
|
||||
colorGradientEnd: 'rgba(245, 240, 232, 0.2)',
|
||||
},
|
||||
|
||||
Spin: {
|
||||
colorPrimary: '#C8363D',
|
||||
dotSize: 20,
|
||||
dotSizeSM: 14,
|
||||
dotSizeLG: 32,
|
||||
},
|
||||
|
||||
Popconfirm: {
|
||||
borderRadiusLG: 12,
|
||||
minWidth: 280,
|
||||
},
|
||||
|
||||
// ===== 其他组件 =====
|
||||
Anchor: {
|
||||
linkPaddingBlock: 4,
|
||||
linkPaddingInlineStart: 16,
|
||||
},
|
||||
|
||||
Segmented: {
|
||||
borderRadius: 8,
|
||||
itemSelectedBg: '#C8363D',
|
||||
itemSelectedColor: '#FFFFFF',
|
||||
itemHoverBg: 'rgba(200, 54, 61, 0.05)',
|
||||
},
|
||||
|
||||
Watermark: {
|
||||
colorFill: 'rgba(0, 0, 0, 0.05)',
|
||||
fontSize: 16,
|
||||
},
|
||||
}
|
||||
|
||||
// 导出类型
|
||||
export type ComponentTokens = typeof componentTokens
|
||||
27
src/theme/index.ts
Normal file
27
src/theme/index.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 非遗文化传承网站 - 主题配置入口
|
||||
* 整合 Token 和组件样式,用于 ConfigProvider
|
||||
*/
|
||||
|
||||
import type { ThemeConfig } from 'antd'
|
||||
import { themeTokens } from './tokens'
|
||||
import { componentTokens } from './components'
|
||||
|
||||
/**
|
||||
* Ant Design 主题配置
|
||||
* 基于中国传统色彩体系,打造具有非遗文化特色的视觉风格
|
||||
*/
|
||||
export const heritageTheme: ThemeConfig = {
|
||||
token: themeTokens,
|
||||
components: componentTokens,
|
||||
cssVar: true, // 启用 CSS 变量
|
||||
hashed: true, // 启用样式哈希
|
||||
}
|
||||
|
||||
// 导出子模块
|
||||
export { themeTokens } from './tokens'
|
||||
export { componentTokens } from './components'
|
||||
|
||||
// 导出类型
|
||||
export type { ThemeTokens } from './tokens'
|
||||
export type { ComponentTokens } from './components'
|
||||
90
src/theme/tokens.ts
Normal file
90
src/theme/tokens.ts
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 非遗文化传承网站 - 主题 Token 配置
|
||||
* 基于中国传统色彩体系设计
|
||||
*/
|
||||
|
||||
export const themeTokens = {
|
||||
// ===== 主色调 =====
|
||||
colorPrimary: '#C8363D', // 朱砂红 - 象征传统文化的热情与活力
|
||||
colorInfo: '#4A5F7F', // 青黛蓝 - 象征深邃与智慧
|
||||
colorSuccess: '#52C41A', // 成功绿
|
||||
colorWarning: '#FAAD14', // 警告黄
|
||||
colorError: '#FF4D4F', // 错误红
|
||||
|
||||
// ===== 辅助色 =====
|
||||
colorAccent: '#D4A574', // 金沙黄 - 象征精湛与珍贵
|
||||
colorAuxiliary1: '#2A5E4D', // 墨绿 - 象征沉稳与生命力
|
||||
colorAuxiliary2: '#4A5F7F', // 青黛蓝
|
||||
|
||||
// ===== 背景色系统 =====
|
||||
colorBgBase: '#FAFAF8', // 宣纸色 - 基础背景
|
||||
colorBgContainer: '#FFFFFF', // 纯白 - 容器背景
|
||||
colorBgElevated: '#FFFFFF', // 浮层背景
|
||||
colorBgLayout: '#F5F0E8', // 浅米黄 - 布局背景
|
||||
colorBgSection: '#F5F0E8', // Section 背景
|
||||
|
||||
// ===== 文本色系统 =====
|
||||
colorTextBase: '#2C2C2C', // 深灰黑 - 主文本
|
||||
colorText: '#2C2C2C', // 主文本
|
||||
colorTextSecondary: '#666666', // 中灰 - 次要文本
|
||||
colorTextTertiary: '#999999', // 浅灰 - 辅助文本
|
||||
colorTextQuaternary: '#CCCCCC', // 极浅灰 - 占位文本
|
||||
|
||||
// ===== 边框色 =====
|
||||
colorBorder: '#E8E3DB', // 主边框色
|
||||
colorBorderSecondary: '#F0EBE3', // 次要边框色
|
||||
|
||||
// ===== 圆角系统 =====
|
||||
borderRadius: 8, // 基础圆角
|
||||
borderRadiusLG: 12, // 大圆角
|
||||
borderRadiusSM: 6, // 小圆角
|
||||
borderRadiusXS: 4, // 极小圆角
|
||||
|
||||
// ===== 字体系统 =====
|
||||
fontSize: 14, // 基础字号
|
||||
fontSizeLG: 16, // 大字号
|
||||
fontSizeSM: 12, // 小字号
|
||||
fontSizeHeading1: 38, // 标题1
|
||||
fontSizeHeading2: 30, // 标题2
|
||||
fontSizeHeading3: 24, // 标题3
|
||||
fontSizeHeading4: 20, // 标题4
|
||||
fontSizeHeading5: 16, // 标题5
|
||||
|
||||
// 字体家族
|
||||
fontFamily: `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
|
||||
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||
'Noto Color Emoji', 'Noto Sans SC', 'Microsoft YaHei'`,
|
||||
|
||||
fontFamilySerif: `'Noto Serif SC', 'Songti SC', Georgia, serif`,
|
||||
|
||||
// ===== 行高 =====
|
||||
lineHeight: 1.5715,
|
||||
lineHeightHeading1: 1.2,
|
||||
lineHeightHeading2: 1.3,
|
||||
lineHeightHeading3: 1.35,
|
||||
|
||||
// ===== 阴影系统 =====
|
||||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
|
||||
boxShadowSecondary: '0 4px 16px rgba(0, 0, 0, 0.12)',
|
||||
boxShadowTertiary: '0 6px 24px rgba(0, 0, 0, 0.16)',
|
||||
|
||||
// ===== 控件高度 =====
|
||||
controlHeight: 40, // 基础控件高度
|
||||
controlHeightLG: 48, // 大控件高度
|
||||
controlHeightSM: 32, // 小控件高度
|
||||
controlHeightXS: 24, // 极小控件高度
|
||||
|
||||
// ===== 动画 =====
|
||||
motionUnit: 0.1,
|
||||
motionBase: 0,
|
||||
motionEaseInOut: 'cubic-bezier(0.645, 0.045, 0.355, 1)',
|
||||
motionEaseOut: 'cubic-bezier(0.215, 0.61, 0.355, 1)',
|
||||
|
||||
// ===== 其他 =====
|
||||
wireframe: false, // 关闭线框模式
|
||||
zIndexBase: 0,
|
||||
zIndexPopupBase: 1000,
|
||||
}
|
||||
|
||||
// 导出类型
|
||||
export type ThemeTokens = typeof themeTokens
|
||||
317
src/types/index.ts
Normal file
317
src/types/index.ts
Normal file
@ -0,0 +1,317 @@
|
||||
/**
|
||||
* 非遗文化传承网站 - TypeScript 类型定义
|
||||
*/
|
||||
|
||||
// ===== 非遗项目类型 =====
|
||||
export interface HeritageItem {
|
||||
id: string
|
||||
name: string
|
||||
category: HeritageCategory
|
||||
province: string
|
||||
city?: string
|
||||
level: HeritageLevel
|
||||
coverImage: string
|
||||
images?: string[]
|
||||
description: string
|
||||
history: string
|
||||
skills: string
|
||||
significance: string
|
||||
inheritors: string[] // 传承人ID列表
|
||||
relatedWorks?: Work[]
|
||||
videoUrl?: string
|
||||
virtualTourUrl?: string
|
||||
status: 'active' | 'endangered' | 'revived'
|
||||
tags: string[]
|
||||
viewCount: number
|
||||
likeCount: number
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
// 非遗分类
|
||||
export type HeritageCategory =
|
||||
| 'folk-literature' // 民间文学
|
||||
| 'traditional-music' // 传统音乐
|
||||
| 'traditional-dance' // 传统舞蹈
|
||||
| 'traditional-opera' // 传统戏剧
|
||||
| 'folk-art' // 曲艺
|
||||
| 'sports-acrobatics' // 传统体育、游艺与杂技
|
||||
| 'traditional-craft' // 传统技艺
|
||||
| 'traditional-medicine'// 传统医药
|
||||
| 'folk-custom' // 民俗
|
||||
| 'traditional-art' // 传统美术
|
||||
|
||||
// 非遗级别
|
||||
export type HeritageLevel =
|
||||
| 'world' // 世界级
|
||||
| 'national' // 国家级
|
||||
| 'provincial' // 省级
|
||||
| 'municipal' // 市级
|
||||
| 'county' // 县级
|
||||
|
||||
// ===== 传承人类型 =====
|
||||
export interface Inheritor {
|
||||
id: string
|
||||
name: string
|
||||
avatar: string
|
||||
coverImage?: string
|
||||
gender: 'male' | 'female'
|
||||
birthYear: number
|
||||
province: string
|
||||
city?: string
|
||||
level: 'national' | 'provincial' | 'municipal'
|
||||
heritageItems: string[] // 关联的非遗项目ID
|
||||
title: string // 称号:如"国家级代表性传承人"
|
||||
bio: string
|
||||
masterSkills: string
|
||||
achievements: Achievement[]
|
||||
awards: Award[]
|
||||
works: Work[]
|
||||
videos: Video[]
|
||||
contactInfo?: ContactInfo
|
||||
socialMedia?: SocialMedia
|
||||
followers: number
|
||||
viewCount: number
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export interface Achievement {
|
||||
id: string
|
||||
title: string
|
||||
description: string
|
||||
date: string
|
||||
images?: string[]
|
||||
}
|
||||
|
||||
export interface Award {
|
||||
id: string
|
||||
name: string
|
||||
level: string
|
||||
year: number
|
||||
organization: string
|
||||
}
|
||||
|
||||
export interface Work {
|
||||
id: string
|
||||
name: string
|
||||
image: string
|
||||
description: string
|
||||
year: number
|
||||
materials?: string
|
||||
dimensions?: string
|
||||
price?: number
|
||||
}
|
||||
|
||||
export interface Video {
|
||||
id: string
|
||||
title: string
|
||||
cover: string
|
||||
url: string
|
||||
duration: number // 秒
|
||||
description?: string
|
||||
viewCount: number
|
||||
publishDate: string
|
||||
}
|
||||
|
||||
export interface ContactInfo {
|
||||
phone?: string
|
||||
email?: string
|
||||
address?: string
|
||||
website?: string
|
||||
}
|
||||
|
||||
export interface SocialMedia {
|
||||
weibo?: string
|
||||
wechat?: string
|
||||
douyin?: string
|
||||
bilibili?: string
|
||||
}
|
||||
|
||||
// ===== 活动与资讯类型 =====
|
||||
export interface NewsArticle {
|
||||
id: string
|
||||
title: string
|
||||
subtitle?: string
|
||||
cover: string
|
||||
category: 'exhibition' | 'activity' | 'policy' | 'research' | 'story'
|
||||
content: string
|
||||
summary: string
|
||||
author: string
|
||||
publishDate: string
|
||||
tags: string[]
|
||||
viewCount: number
|
||||
likeCount: number
|
||||
relatedHeritage?: string[]
|
||||
relatedInheritors?: string[]
|
||||
}
|
||||
|
||||
export interface Event {
|
||||
id: string
|
||||
title: string
|
||||
cover: string
|
||||
type: 'exhibition' | 'workshop' | 'performance' | 'lecture' | 'festival'
|
||||
location: string
|
||||
address: string
|
||||
startDate: string
|
||||
endDate: string
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
description: string
|
||||
organizer: string
|
||||
capacity?: number
|
||||
enrolled: number
|
||||
price: number
|
||||
isFree: boolean
|
||||
tags: string[]
|
||||
status: 'upcoming' | 'ongoing' | 'finished' | 'cancelled'
|
||||
registrationRequired: boolean
|
||||
contactInfo: ContactInfo
|
||||
relatedHeritage?: string[]
|
||||
images: string[]
|
||||
viewCount: number
|
||||
}
|
||||
|
||||
// ===== 用户相关类型 =====
|
||||
export interface User {
|
||||
id: string
|
||||
username: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
email: string
|
||||
phone?: string
|
||||
bio?: string
|
||||
favorites: string[] // 收藏的非遗项目ID
|
||||
followedInheritors: string[] // 关注的传承人ID
|
||||
enrolledCourses: string[] // 已报名课程ID
|
||||
registeredEvents: string[] // 已报名活动ID
|
||||
points: number
|
||||
level: number
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
// ===== 体验相关类型 =====
|
||||
export interface VirtualTour {
|
||||
id: string
|
||||
title: string
|
||||
cover: string
|
||||
description: string
|
||||
panoramaUrl: string
|
||||
hotspots: Hotspot[]
|
||||
heritageId: string
|
||||
}
|
||||
|
||||
export interface Hotspot {
|
||||
id: string
|
||||
position: { x: number; y: number; z: number }
|
||||
title: string
|
||||
description: string
|
||||
mediaType: 'image' | 'video' | 'audio' | 'text'
|
||||
mediaUrl?: string
|
||||
}
|
||||
|
||||
export interface Workshop {
|
||||
id: string
|
||||
title: string
|
||||
cover: string
|
||||
heritageId: string
|
||||
inheritorId: string
|
||||
location: string
|
||||
address: string
|
||||
duration: number // 小时
|
||||
maxParticipants: number
|
||||
enrolled: number
|
||||
price: number
|
||||
dates: string[] // 可预约日期
|
||||
description: string
|
||||
whatToLearn: string[]
|
||||
requirements: string[]
|
||||
providedMaterials: string[]
|
||||
}
|
||||
|
||||
// ===== 统计数据类型 =====
|
||||
export interface Statistics {
|
||||
totalHeritageItems: number
|
||||
totalInheritors: number
|
||||
totalProvinces: number
|
||||
totalCities: number
|
||||
worldHeritage: number
|
||||
nationalHeritage: number
|
||||
provincialHeritage: number
|
||||
endangeredCount: number
|
||||
activePreservation: number
|
||||
}
|
||||
|
||||
// ===== 通用类型 =====
|
||||
export interface PaginationParams {
|
||||
page: number
|
||||
pageSize: number
|
||||
}
|
||||
|
||||
export interface PaginationResult<T> {
|
||||
data: T[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
|
||||
export interface FilterParams {
|
||||
category?: HeritageCategory | HeritageCategory[]
|
||||
level?: HeritageLevel | HeritageLevel[]
|
||||
province?: string | string[]
|
||||
type?: string | string[]
|
||||
status?: string | string[]
|
||||
search?: string
|
||||
sortBy?: 'name' | 'viewCount' | 'likeCount' | 'createdAt'
|
||||
sortOrder?: 'asc' | 'desc'
|
||||
}
|
||||
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
timestamp: number
|
||||
}
|
||||
|
||||
// ===== 评论类型 =====
|
||||
export interface Comment {
|
||||
id: string
|
||||
userId: string
|
||||
userName: string
|
||||
userAvatar: string
|
||||
targetType: 'heritage' | 'inheritor' | 'news'
|
||||
targetId: string
|
||||
content: string
|
||||
rating?: number // 1-5 评分
|
||||
images?: string[]
|
||||
likeCount: number
|
||||
replyCount: number
|
||||
replies?: Comment[]
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
// ===== 搜索相关类型 =====
|
||||
export interface SearchResult {
|
||||
type: 'heritage' | 'inheritor' | 'news'
|
||||
id: string
|
||||
title: string
|
||||
subtitle?: string
|
||||
cover: string
|
||||
description: string
|
||||
tags: string[]
|
||||
score: number // 搜索相关度评分
|
||||
}
|
||||
|
||||
export interface SearchResults {
|
||||
heritages: HeritageItem[]
|
||||
inheritors: Inheritor[]
|
||||
news: NewsArticle[]
|
||||
}
|
||||
|
||||
export interface SearchHistory {
|
||||
id: string
|
||||
keyword: string
|
||||
timestamp: string
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user