feat: refine login flows and integrate tiangong worship audio

This commit is contained in:
zhouzhibo committed 2026-10-18 23:35:28 +08:00
1 parent bc7bbc52c8
commit 38fc4187ea
49 files changed
+1786 -224

No files matched your search

+17 -8
View File
@@ -3,24 +3,35 @@ import Taro from '@tarojs/taro'
import { Button, Image, Text, View } from '@tarojs/components'
import { AppTabBar } from '../../components/AppTabBar'
import { TiangongHeader, TiangongMockNote, TiangongModal } from '../../components/TiangongUI'
import { deityCatalog, tiangongMock } from '../../services/tiangong'
import { deityCatalog, isTiangongDemo, tiangongMock, tiangongSession } from '../../services/tiangong'
import { resolveAssetUrl } from '../../services/request'
import { useTiangongSnapshot } from '../../hooks/useTiangongSnapshot'
import { DeityId } from '../../utils/tiangongMock'
import { hasLoginAccess } from '../../services/loginAccess'
import { useRequiredLogin } from '../../hooks/useRequiredLogin'
import { TiangongLoginGate } from '../../components/TiangongLoginGate'
import './index.scss'
export default function FortunePage() {
const auth = useRequiredLogin()
if (auth.status !== 'allowed' || !hasLoginAccess()) return <TiangongLoginGate status={auth.status === 'allowed' ? 'denied' : auth.status} retry={auth.retry} tab />
return <FortuneContent />
}
function FortuneContent() {
const snapshot = useTiangongSnapshot()
const items = deityCatalog.map(item => ({ ...item, ...snapshot.deities[item.id] }))
const [selected, setSelected] = useState<DeityId | null>(null)
const [settings, setSettings] = useState(false)
const balance = snapshot.balance
const open = (id: DeityId, invite = false) => Taro.navigateTo({ url: `/pages/tiangong-detail/index?id=${id}${invite ? '&mode=invite' : ''}` })
return <View className='tiangong-page'>
<TiangongHeader title='天宫' /><TiangongMockNote />
{snapshot.loading && !snapshot.ready && <Text className='tg-data-note'>正在加载神仙列表…</Text>}
{snapshot.error && <View className='tg-data-note'><Text>{snapshot.error}</Text><Button onClick={() => tiangongSession.refresh(true).catch(() => {})}>重新加载</Button></View>}
<View className='deity-grid'>
{items.map(item => <View className='deity-card-wrap' key={item.id}>
<Button className={`deity-card ${item.unlocked ? 'unlocked' : 'locked'}`} aria-label={`${item.name},${item.unlocked ? '已恭请' : '未恭请'}`} onClick={() => item.unlocked ? open(item.id) : setSelected(selected === item.id ? null : item.id)}>
<Image className='deity-image' src={item.icon} mode='aspectFill' /><Text className='deity-name'>{item.name}</Text>
<Button disabled={item.available === false} className={`deity-card ${item.unlocked ? 'unlocked' : 'locked'}`} aria-label={`${item.name},${item.unlocked ? '已恭请' : '未恭请'}`} onClick={() => item.unlocked ? open(item.id) : setSelected(selected === item.id ? null : item.id)}>
<Image className='deity-image' src={resolveAssetUrl(item.iconUrl) || item.icon} mode='aspectFill' /><Text className='deity-name'>{item.name}{item.available === false && snapshot.ready ? '(暂未配置)' : ''}</Text>
</Button>
{selected === item.id && !item.unlocked && <View className='deity-invite-prompt'>
<Button className='deity-prompt-close' aria-label='关闭恭请提示' onClick={() => setSelected(null)}>×</Button>
@@ -29,11 +40,9 @@ export default function FortunePage() {
</View>}
</View>)}
</View>
<Button className='tg-demo-settings' onClick={() => setSettings(true)}>Mock 演示设置</Button>
{isTiangongDemo() && <Button className='tg-demo-settings' onClick={() => setSettings(true)}>Mock 演示设置</Button>}
{settings && <TiangongModal title='Mock 演示设置' onClose={() => setSettings(false)} variant='plain'>
<Text className='tg-modal-title'>Mock 演示设置</Text><Text className='tg-modal-copy'>当前模拟爱心:{balance}</Text>
<Text className='tg-modal-caption'>仅切换演示余额,不是充值。刷新网页或重新启动小程序后恢复初始样例。</Text>
<View className='tg-modal-actions'>{([0, 100] as const).map(value => <Button className='tg-button' key={value} onClick={() => tiangongMock.setDemoBalance(value)}>设为 {value}</Button>)}</View>
<Text className='tg-modal-title'>Mock 演示设置</Text><Text className='tg-modal-caption'>仅重置本次演示,不修改真实供奉记录。</Text>
<View className='tg-modal-actions'><Button className='tg-button' onClick={() => { tiangongMock.reset(); setSelected(null); setSettings(false) }}>重置全部演示</Button></View>
</TiangongModal>}
<AppTabBar active='fortune' />