更新依赖项及历史人物相关内容资源
- 更新 package.json 和 package-lock.json 中的依赖项 - 新增/更新陈云、黄炎培、鲁迅、孙中山的音频文件 - 新增场景和组件的图片资源 - 清理未使用的音频和图片文件 - 优化多个组件和页面的实现逻辑
This commit is contained in:
1 parent
b1d55b9464
commit
e0fa47d21a
629 files changed
+24390
-2991
No files matched your search
@@ -0,0 +1,233 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Image } from '@/components'
|
||||
import { cn, getBackgroundImage, getStaticImage } from '@/lib/utils'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { saveZhanglepingStore, useZhanglepingStore } from '@/store/zhanglepingStore'
|
||||
import {
|
||||
type BackgroundKey,
|
||||
type ClothesKey,
|
||||
type MaterialKey,
|
||||
type SidebarBlockKey,
|
||||
STAR_NAME,
|
||||
backgroundToAllowedMaterials,
|
||||
buildCompositeDataUrl,
|
||||
getBackgroundAssetKey,
|
||||
materialConflicts,
|
||||
materialOptions,
|
||||
sidebarBlocks,
|
||||
} from './draw1.config'
|
||||
import { TopMenuPanel } from './TopMenuPanel'
|
||||
|
||||
const ZhanglepingDraw1 = () => {
|
||||
const navigate = useNavigate()
|
||||
const { moduleName } = useParams<{ moduleName: string }>()
|
||||
const { setDrawArtwork } = useZhanglepingStore()
|
||||
|
||||
const [activeBlock, setActiveBlock] = useState<SidebarBlockKey>('衣柜')
|
||||
const [selectedClothes, setSelectedClothes] = useState<ClothesKey>('默认')
|
||||
const [selectedBackground, setSelectedBackground] = useState<BackgroundKey>('城际高铁')
|
||||
const [selectedMaterials, setSelectedMaterials] = useState<Set<MaterialKey>>(new Set())
|
||||
const [showCaptionInput, setShowCaptionInput] = useState(false)
|
||||
const [captionText, setCaptionText] = useState('')
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
|
||||
const captionInputRef = useRef<HTMLInputElement>(null)
|
||||
const compositionRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const allowedMaterialKeys = useMemo(
|
||||
() => backgroundToAllowedMaterials[selectedBackground] ?? [],
|
||||
[selectedBackground]
|
||||
)
|
||||
const backgroundAssetKey = getBackgroundAssetKey(selectedBackground)
|
||||
|
||||
const scenePreviewSrc = `${STAR_NAME}/reflection/draw/布景/${backgroundAssetKey}`
|
||||
const clothingSrc = `${STAR_NAME}/reflection/draw/衣柜/${selectedClothes}`
|
||||
const boardBgSrc = `${STAR_NAME}/reflection/draw/画板底图`
|
||||
|
||||
// 切换布景后:移除不允许的素材
|
||||
useEffect(() => {
|
||||
setSelectedMaterials((prev) => {
|
||||
const next = new Set([...prev].filter((k) => allowedMaterialKeys.includes(k)))
|
||||
return next.size === prev.size ? prev : next
|
||||
})
|
||||
}, [allowedMaterialKeys])
|
||||
|
||||
useEffect(() => {
|
||||
if (showCaptionInput) captionInputRef.current?.focus()
|
||||
}, [showCaptionInput])
|
||||
|
||||
const handleToggleMaterial = (key: MaterialKey) => {
|
||||
setSelectedMaterials((prev) => {
|
||||
const next = new Set(prev)
|
||||
if (next.has(key)) {
|
||||
next.delete(key)
|
||||
return next
|
||||
}
|
||||
const conflicts = materialConflicts[key] ?? []
|
||||
for (const c of conflicts) next.delete(c)
|
||||
if (next.size < 3) next.add(key)
|
||||
return next
|
||||
})
|
||||
}
|
||||
|
||||
const handleSubmitArtwork = async () => {
|
||||
if (!showCaptionInput) {
|
||||
setShowCaptionInput(true)
|
||||
return
|
||||
}
|
||||
if (isSubmitting) return
|
||||
|
||||
setIsSubmitting(true)
|
||||
try {
|
||||
const dataUrl = await buildCompositeDataUrl(compositionRef.current!)
|
||||
setDrawArtwork(dataUrl, captionText.trim())
|
||||
saveZhanglepingStore()
|
||||
navigate(`/${moduleName}/${STAR_NAME}/reflection5`)
|
||||
} catch (error) {
|
||||
console.error('Failed to submit draw artwork', error)
|
||||
} finally {
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
const isPreviewVisible = activeBlock !== '任务提示'
|
||||
|
||||
if (!moduleName) return null
|
||||
|
||||
return (
|
||||
<div
|
||||
className="w-full h-full relative overflow-hidden bg-cover bg-center bg-no-repeat"
|
||||
style={{ backgroundImage: getBackgroundImage(boardBgSrc) }}
|
||||
>
|
||||
{/* 中央预览区 */}
|
||||
<div
|
||||
ref={compositionRef}
|
||||
className="absolute left-20 bottom-[86px] w-[1605px] h-[904px] bg-cover bg-center bg-no-repeat"
|
||||
style={{ backgroundImage: getBackgroundImage(scenePreviewSrc) }}
|
||||
>
|
||||
<div className="relative w-full h-full">
|
||||
{isPreviewVisible && (
|
||||
<div className="absolute left-111 bottom-0 z-10">
|
||||
<Image src={getStaticImage(clothingSrc)} alt="衣柜选项" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isPreviewVisible &&
|
||||
materialOptions
|
||||
.filter((opt) => selectedMaterials.has(opt.key))
|
||||
.map((opt) => (
|
||||
<div
|
||||
key={opt.key}
|
||||
className={cn('absolute', opt.key === '车' ? 'z-8' : 'z-20')}
|
||||
data-material-key={opt.key}
|
||||
style={{
|
||||
top: opt.position.top,
|
||||
left: opt.position.left,
|
||||
bottom: opt.position.bottom,
|
||||
right: opt.position.right,
|
||||
}}
|
||||
>
|
||||
<Image src={getStaticImage(opt.assetSrc)} alt={opt.key} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 顶部菜单 */}
|
||||
<div className="absolute left-0 top-4 z-30 w-full">
|
||||
<TopMenuPanel
|
||||
activeBlock={activeBlock}
|
||||
selectedClothes={selectedClothes}
|
||||
selectedBackground={selectedBackground}
|
||||
selectedMaterials={selectedMaterials}
|
||||
allowedMaterialKeys={allowedMaterialKeys}
|
||||
onSelectClothes={setSelectedClothes}
|
||||
onSelectBackground={setSelectedBackground}
|
||||
onToggleMaterial={handleToggleMaterial}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 任务提示窗口 */}
|
||||
{activeBlock === '任务提示' && (
|
||||
<div
|
||||
className="absolute left-8 top-[26%] z-30 w-[1724px] h-[424px] bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: getBackgroundImage(`${STAR_NAME}/reflection/draw/创作任务面板`),
|
||||
backgroundSize: '100% 100%',
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-center pt-28">
|
||||
<div className="w-full text-center text-[#8B6914] font-medium leading-tight">
|
||||
<div className="text-3xl space-y-8">
|
||||
<div>①为三毛换装</div>
|
||||
<div>②搭配1个新时代场景</div>
|
||||
<div>③融入1-3个新时代元素</div>
|
||||
<div>④配1句简短正能量文字</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 右侧侧边栏 */}
|
||||
<div className="absolute right-[4px] top-[162px] z-40 w-[162px]">
|
||||
<div className="flex flex-col gap-4">
|
||||
{sidebarBlocks.map((blk) => (
|
||||
<button key={blk.key} type="button" onClick={() => setActiveBlock(blk.key)}>
|
||||
<Image
|
||||
className={cn(activeBlock === blk.key ? 'opacity-100' : 'opacity-60')}
|
||||
src={getStaticImage(blk.iconSrc)}
|
||||
alt={blk.key}
|
||||
/>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 底部输入框 */}
|
||||
{showCaptionInput && (
|
||||
<div
|
||||
className="absolute left-20 bottom-2.5 bg-cover bg-center bg-no-repeat w-[1724px] h-[100px] z-40"
|
||||
style={{ backgroundImage: getBackgroundImage(`${STAR_NAME}/reflection/draw/写字底板`) }}
|
||||
>
|
||||
<div className="flex items-center justify-center">
|
||||
<input
|
||||
ref={captionInputRef}
|
||||
type="text"
|
||||
id="textInput"
|
||||
name="textInput"
|
||||
maxLength={15}
|
||||
value={captionText}
|
||||
onChange={(e) => setCaptionText(Array.from(e.target.value).slice(0, 15).join(''))}
|
||||
className={cn(
|
||||
'w-200 h-24 bg-transparent',
|
||||
'text-4xl! text-[#8B6914] leading-none placeholder:text-3xl!'
|
||||
)}
|
||||
autoComplete="off"
|
||||
placeholder="提交之前,请给你创作的我配一句简短的正能量文字吧!"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 底部按钮 */}
|
||||
<div className="absolute -left-10 bottom-0 z-50">
|
||||
<Image
|
||||
src={getStaticImage(`${STAR_NAME}/reflection/draw/返回`)}
|
||||
button
|
||||
onClick={() => navigate(`/${moduleName}/${STAR_NAME}/draw`)}
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute -right-10 bottom-0 z-50">
|
||||
<Image
|
||||
src={getStaticImage(`${STAR_NAME}/reflection/draw/提交作品`)}
|
||||
button
|
||||
className={isSubmitting ? 'opacity-70 pointer-events-none' : undefined}
|
||||
onClick={handleSubmitArtwork}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ZhanglepingDraw1
|
||||
Reference in new issue
Block a user