import { useMemo, useState } from 'react' import { getBackgroundImage, getStaticImage } from '@/lib/utils' import { usePuzzleStore } from '@/store/puzzleStore' import { Image } from '@/components' import { PUZZLE_RESIDENCES } from '@/config/puzzleResidences' /** * 六边形进度条组件 * 根据进度值显示不同颜色:100%绿色,50%-99%橙色,0%-49%灰色 */ interface HexagonProgressBarProps { progress: number // 0-100 } const HexagonProgressBar = ({ progress }: HexagonProgressBarProps) => { const progressPercent = Math.min(100, Math.max(0, progress)) const progressText = progressPercent.toFixed(2) === '100.00' ? '进度100%' : `进度${Math.round(progressPercent)}%` // 根据进度值确定填充颜色 const getProgressColor = () => { if (progressPercent >= 100) { return '#90B86B' // 浅橄榄绿色(100%完成) } else if (progressPercent >= 50) { return '#EEB362' // 橙色(50%-99%) } else { return '#E0E0E0' // 浅灰色(0%-49%) } } const fillColor = getProgressColor() // 六边形路径,细长的水平六边形,左右两端是尖角 // 正确的六边形路径:从左顶点开始,顺时针绘制 // 左顶点(0%, 50%) -> 左上角(3%, 0%) -> 右上角(97%, 0%) -> 右顶点(100%, 50%) -> 右下角(97%, 100%) -> 左下角(3%, 100%) // 外层路径(包含边框) const outerHexagonPath = 'polygon(0% 50%, 3% 0%, 97% 0%, 100% 50%, 97% 100%, 3% 100%)' // 内层路径(边框内部) const innerHexagonPath = 'polygon(0% 50%, 3% 0%, 97% 0%, 100% 50%, 97% 100%, 3% 100%)' const borderWidth = 4 // 增加边框宽度从2px到3px return (
{/* 外层:白色边框(使用 clip-path 裁剪形状) */}
{/* 内容容器(边框内部区域) */}
{/* 背景层:深灰色背景(未填充部分) */}
{/* 填充层(根据进度百分比从左侧填充) */} {progressPercent > 0 && (
)}
{/* 文字(白色,居中,始终显示在最上层,带阴影效果) */}
{progressText}
) } export interface MenuPuzzleCenterProps { /** 是否可见 */ visible: boolean /** 关闭回调 */ onClose: () => void /** 选择某个故居后的回调(进入对应的碎片系统) */ onSelectResidence: (residence: string) => void /** 是否允许从管理中心进入具体拼图 */ allowPuzzleEntry?: boolean } const MenuPuzzleCenter = ({ visible, onClose, onSelectResidence, allowPuzzleEntry = true, }: MenuPuzzleCenterProps) => { const { getPuzzleCollectProgress } = usePuzzleStore() const [activeMapImage, setActiveMapImage] = useState(null) const residenceProgress = useMemo( () => PUZZLE_RESIDENCES.map((item) => ({ ...item, // 只有已开放拼图的故居才计算收集进度 progress: item.hasPuzzle ? getPuzzleCollectProgress(item.residence) : 0, })), [getPuzzleCollectProgress] ) if (!visible) return null return (
{ if (e.target === e.currentTarget) { onClose() } }} >
{/* 箭头指示底图 */} {/* 关闭按钮 */} 关闭 {/* 故居列表:按照设计图进行绝对定位 */}
{residenceProgress.map( ({ residence, displayName, left, top, image, hasPuzzle, progress, hasMap, mapImage, }) => (
{/* 故居图片(资源在 puzzle/home 下,可根据实际名称调整) */} {displayName} {/* 进度展示,仅对已开放拼图的故居显示 */} {hasPuzzle && (
)} {/* 图标 */}
{allowPuzzleEntry && ( 拼图 { if (!hasPuzzle) return e.stopPropagation() onSelectResidence(residence) }} /> )} 导图 { e.stopPropagation() if (!hasMap || !mapImage) return setActiveMapImage(mapImage) }} />
) )}
{/* 导图弹窗 */} {activeMapImage && (
{ if (e.target === e.currentTarget) { setActiveMapImage(null) } }} >
关闭 setActiveMapImage(null)} /> 导图
)}
) } export default MenuPuzzleCenter